仅当参数为非负数时才定义sqrt [英] sqrt is only defined when argument is nonnegative

查看:204
本文介绍了仅当参数为非负数时才定义sqrt的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这样可以编译

#include <math.h>

int main(void) {
    double i = sqrt(9.0);
}

如果将9.0更改为-9.0,则我的编译器(GNU C)给出有关未定义引用'sqrt'的错误.

If I change 9.0 to -9.0, then my compiler (GNU C) gives an error about an undefined reference to 'sqrt'.

我期望sqrt函数返回NaN或异常. C库如何仅为非负参数定义sqrt?

I was expecting the sqrt function to return NaN or an exception. How does the C library only define sqrt for non-negative arguments?

推荐答案

之所以会发生这种情况,是因为gcc可以在优化过程中使用内置函数在编译时计算某些函数,包括sqrt在许多但并非全部情况下.如果是这种情况,它将不需要发出对sqrt的调用,因此不需要链接到libm.

This is happening because gcc can use builtin functions during the optimization process to compute certain functions including sqrt at compile time in many but not all cases. If that is the case it will not need to emit a call to sqrt and therefore will not need to link against libm.

gcc文档具有内置列表的完整列表,并且说(强调我的):

The gcc documents have a complete list of builtins, and it says (emphasis mine):

出于优化目的提供了其余功能.

The remaining functions are provided for optimization purposes.

GCC在标准C库中包含许多功能的内置版本.带有_ builtin 前缀的版本始终被视为与C库函数具有相同的含义,即使您指定了-fno-builtin选项. (请参阅C语言选项).其中许多功能仅在某些情况下经过优化;如果在特定情况下未对它们进行优化,则会发出对库函数的调用.

GCC includes built-in versions of many of the functions in the standard C library. The versions prefixed with _builtin are always treated as having the same meaning as the C library function even if you specify the -fno-builtin option. (see C Dialect Options) Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function is emitted.

如果我使用gcc -S编译此代码并查看发出的程序集( 实时例如 ),当我们使用sqrt(9.0)时,gcc将使用内置函数,并且不会发出对 sqrt 的调用,因为它将在编译时进行计算.如果我们更改代码以使用sqrt(-9.0),它将立即发出( 实时示例 ):

If I compile this code with gcc -S and look at the assembly emitted(live example) when we use sqrt(9.0) then gcc will use a builtin and not emit a call to sqrt at all since it will compute it at compile time. If we change the code to use sqrt(-9.0) it will now emit(live example):

call    sqrt

这需要与libm链接,解决方法是将-lm添加到编译选项的末尾.

which will require linking with libm, the fix would be to add -lm to the end of your compile options.

对于sqrt(-9),我们有一个域错误,如果转到C99草案标准部分7.12.7.5 sqrt函数段落 2 说(强调我的):

In the case of sqrt(-9) we have a domain error, if go to the C99 draft standard section 7.12.7.5 The sqrt functions paragraph 2 says (emphasis mine):

sqrt函数计算x的非负平方根. 如果发生域错误 该参数小于零.

The sqrt functions compute the nonnegative square root of x. A domain error occurs if the argument is less than zero.

如果我们回到7.12.1 错误条件的处理,它会说:

If we go back to 7.12.1 Treatment of error conditions it says:

[...]在域错误时,该函数返回实现定义的值;如果整数表达式 math_errhandling& MATH_ERRNO 为非零,整数表达式 errno获得值 EDOM ;如果整数表达式 math_errhandling& MATH_ERREXCEPT 不为零,则引发无效"浮点异常.

[...] On a domain error, the function returns an implementation-defined value; if the integer expression math_errhandling & MATH_ERRNO is nonzero, the integer expression errno acquires the value EDOM; if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero, the ‘‘invalid’’ floating-point exception is raised.

因此将设置 errno 和/或引发 floating point 异常,这似乎是gcc认为优化效率不高的情况

so either errno will be set and/or a floating point exception will be raised which seems like a case where gcc would decided it is not efficient to optimize.

这篇关于仅当参数为非负数时才定义sqrt的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆