为什么sqrt()在一个int变量上工作正常,如果它没有为int定义的话? [英] Why does sqrt() work fine on an int variable if it is not defined for an int?

查看:179
本文介绍了为什么sqrt()在一个int变量上工作正常,如果它没有为int定义的话?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编程:使用C ++的原则和实践 的第3章(第6次印刷),Stroustrup状态(p.68):注意 sqrt()没有为 int



这是一个简单的基于该章的C ++程序:

  #includestd_lib_facilities.h

int main()
{
int n = 3;
cout<< n ==的平方根<< sqrt(n)<< \\\
;





$ b

考虑到上面的引用,我期望编译或运行这个程序的过程以某种方式失败。

令我吃惊的是,编译它(使用g ++(GCC)4.2.1)并且运行成功,没有错误或警告,并且产生了以下内容完美体面的输出:

  n的平方根== 1.73205 

因此,我的问题是:如果 sqrt()确实没有为 int ,那么为什么上面的程序不会失败? B>



这个问题与一个确切的副本合并在一起,考虑到这一点,实际的答案比任何人原先想象的要简单得多。当前版本的 std_lib_facilities.h 包含以下行:

 内联double sqrt(int x){return sqrt(double(x)); } //匹配C ++ 0x 

它为 int case来匹配现代编译器应该做的事情,即将整型参数转换为double ,尽管这个版本并没有涵盖所有情况。



如果 std_lib_facilities.h 未被使用,但仍然适用原始逻辑,虽然与相比, gcc-4.2 Visual Studio 2012 从原始问题,但 4.1.2 版本已经使用 __ builtin_sqrt 专门用于整数。



原始



自2005年标准草案要求将整数参数转换为 double ,这在草案C ++标准。如果我们查看 26 部分,然后转到 26.8部分 它包含< cmath> 标题,它指定了 float 的数学函数的重载, double long double ,其中涵盖了 8


除了数学函数的双重版本之外,C ++增加了这些函数的float和long double重载版本,具有相同的语义。

对于 int 的情况,它会是 ambiguous ,但是标准要求提供足够的重载,这样整数参数是 cast 转换为 double 。它在 11 段落中有说明(强调我的):


,应该有额外的重载足以确保:



  1. 如果任何对应于双参数的算术参数具有类型long double,则所有对应于double参数的算术参数都被有效地转换为long double。
  2. 否则,如果与double参数对应的算术参数具有double类型或整数类型,则那么所有对应于double参数的算术参数都有效地转换为double。

  3. 否则,与double参数对应的所有算术参数的类型都是float。



更新



由于@nos指出可能调用 sqrt 的版本来自 math.h 标题而不是来自 cmath 的重载,如果是这种情况并且有可能定义一个实现警告,那么我们可以 如果可用的唯一版本是 sqrt(double),这意味着 int 行为会恢复到旧的 C style 行为>将被转换为 double implicitly



我发现在 gcc > clang 应该为 a 使用 long 类型,它与<$如果我们只有 sqrt(double)可用,c $ c> -Wconversion 标志为我的平台上的潜在值更改转换触发警告。事实上,如果我包含 math.h 而不是 cmath ,我们可以产生这个警告。虽然我无法在 clang 中触发这种行为,这似乎表明这是依赖的实现。


In chapter 3 of Programming: Principles and Practice using C++ (sixth printing), Stroustrup states (p.68): "Note that sqrt() is not defined for an int".

Here is a simple C++ program based on that chapter:

#include "std_lib_facilities.h"

int main()
{
    int n = 3;
    cout << "Square root of n == " << sqrt(n) << "\n";
}

Given the quote above, I would expect the process of compiling or running this program to fail in some way.

To my surprise, compiling it (with g++ (GCC) 4.2.1) and running it succeeded without errors or warnings, and produced the following perfectly decent output:

Square root of n == 1.73205

My question therefore is: if sqrt() really is not defined for an int, then why doesn't the program above fail somehow?

解决方案

Update 2

This question was merged with an exact duplicate, on taking a look at this, the actual answer is much simpler than anyone originally thought. The current version of std_lib_facilities.h includes the following line:

inline double sqrt(int x) { return sqrt(double(x)); }   // to match C++0x

which creates a specific overload for the int case to match what modern compilers should be be doing which is cast integer arguments to double, although this version does not cover all the cases.

If std_lib_facilities.h was not being used than the original logic still applies, although gcc-4.2 is rather old compared to Visual Studio 2012 from the original question but a 4.1.2 version have uses __builtin_sqrt specifically for the integer case.

Original

Since around 2005 the draft standard required integer argument to be cast to double this is covered in the draft C++ standard. If we look in section 26 Numerics library and then go to section 26.8 C library which covers the <cmath> header, it specifies overloads of the math functions for float, double and long double which is covered in paragraph 8:

In addition to the double versions of the math functions in , C++ adds float and long double overloaded versions of these functions, with the same semantics.

which would be ambiguous for the int case but the standard requires that sufficient overload are provided so that integer arguments are cast to double. It is covered in paragraph 11 which says(emphasis mine):

Moreover, there shall be additional overloads sufficient to ensure:

  1. If any arithmetic argument corresponding to a double parameter has type long double, then all arithmetic arguments corresponding to double parameters are effectively cast to long double.
  2. Otherwise, if any arithmetic argument corresponding to a double parameter has type double or an integer type, then all arithmetic arguments corresponding to double parameters are effectively cast to double.
  3. Otherwise, all arithmetic arguments corresponding to double parameters have type float.

Update

As @nos points out it is possible that the version of sqrt being called is from math.h header as opposed to the overloads from cmath, if that is the case and there is likely a implementation defined caveat here then we may be reverting to old C style behavior if the only version available is sqrt(double) which would mean that int would be converted to double implicitly.

One way I found to test this on gcc and clang would be to use long type for a which along with -Wconversion flag triggers a warning for a potentially value altering conversion on my platform if we only have sqrt(double) available. Indeed if I include math.h instead of cmath we can produce this warning. Although I can not trigger this behavior in clang which seems to indicate this is implementation dependent.

这篇关于为什么sqrt()在一个int变量上工作正常,如果它没有为int定义的话?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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