C++ 0.1浮动大于0.1倍。我以为这是假的

C++ 0.1浮动大于0.1倍。我以为这是假的,c++,c,floating-point,double,rounding,C++,C,Floating Point,Double,Rounding,让我们: 应该使用表达式吗 double d = 0.1; float f = 0.1; 返回true或false 根据经验,答案是正确。但是,我希望它是false As0.1不能完全用二进制表示,而double具有15到16精度的十进制数字,float只有7。因此,它们都小于0.1,而double更接近0.1 我需要对true的确切解释数字0.1将四舍五入到最接近的浮点表示形式,并具有给定的精度。此近似值可能大于或小于0.1,因此如果不查看实际值,则无法预测单精度近似值或双精度近似值是否更大

让我们:

应该使用表达式吗

double d = 0.1;
float f = 0.1;
返回
true
false

根据经验,答案是
正确
。但是,我希望它是
false

As
0.1
不能完全用二进制表示,而double具有
15
16
精度的十进制数字,float只有
7
。因此,它们都小于
0.1
,而double更接近
0.1


我需要对
true

的确切解释数字0.1将四舍五入到最接近的浮点表示形式,并具有给定的精度。此近似值可能大于或小于0.1,因此如果不查看实际值,则无法预测单精度近似值或双精度近似值是否更大

以下是双精度值的舍入值(使用Python解释器):

以下是单个精度值:

>>> "%.55f" % 0.1
'0.1000000000000000055511151231257827021181583404541015625'

因此,您可以看到单精度近似值更大。

我认为答案取决于将
双精度
转换为
浮点
时的舍入模式
float
有24个二进制精度位,
double
有53个二进制精度位。在二进制中,0.1是:

>>> "%.55f" % numpy.float32("0.1")
'0.1000000014901161193847656250000000000000000000000000000'
所以如果我们在第24位取整,我们会得到

0.1₁₀ = 0.0001100110011001100110011001100110011001100110011…₂
             ^        ^         ^   ^ 
             1       10        20  24

它大于精确值和53位的更精确近似值。

如果将
.1
转换为二进制,则得到:

0.1₁₀ ~ 0.000110011001100110011001101
0.000110011001100110011001100110011001100110011001100... 永远重复

映射到数据类型,您可以得到:

0.000110011001100110011001100110011001100110011001100... 浮动(.1)=%.00011001101 ^---音符四舍五入 双(.1)=%.000110011010 将其转换为基数10:

float(.1) = %.00011001100110011001101 ^--- note rounding double(.1) = %.0001100110011001100110011001100110011001100110011010 浮动(.1)=.10000002384185791015625 双精度(.1)=.1000000000000088817841970012523233890533447265625 这是摘自布鲁斯·道森的一篇文章。可以在这里找到:

除了其他关于IEEE-754和x86的答案之外,这个问题甚至比他们想象的还要复杂。IEEE-754中没有0.1的“一”表示法-有两种。将最后一位数字向下或向上舍入都是有效的。这种差异可以而且确实发生,因为x86不使用64位进行内部浮点计算;它实际上使用80位!这就是所谓的

因此,即使在x86编译器中,有时也会出现相同的数字以两种不同的方式表示的情况,因为有些使用64位计算其二进制表示,而另一些使用80位


事实上,即使在同一个编译器上,甚至在同一台机器上,也可能发生这种情况

float(.1) = .10000002384185791015625 double(.1) = .100000000000000088817841970012523233890533447265625
#包括
#包括
无效foo(双x,双y)
{
如果(std::cos(x)!=std::cos(y)){

std::cout因为它不能精确表示,所以在基数2中比较1/10就像在基数10中比较1/7一样


1/7=0.142857142857…但在不同的基数10精度下进行比较(小数点后3位与6位)我们有0.143>0.142857。

在转换中,double的秩大于float的秩。通过进行逻辑比较,f被转换为double,并且可能您使用的实现给出了不一致的结果。如果您为f加后缀,编译器将其注册为float,那么您将得到0.00,这在double类型中为false。unffifixed float类型是双重的

#include <iostream>
#include <cmath>

void foo(double x, double y)
{
  if (std::cos(x) != std::cos(y)) {
    std::cout << "Huh?!?\n";  //← you might end up here when x == y!!
  }
}

int main()
{
  foo(1.0, 1.0);
  return 0;
}
#包括
#包括
int main()
{
双d=0.1;
浮球f=0.1f;
printf(“%f\n”,(f>d));
返回0;
}
我认为这个问题实际上是最清楚的解释,所以我将把它作为一个答案转发给大家:


假设您正在计算3位小数和6位小数的1/9。0.111<0.111111,对吗

现在假设您正在计算6/9.0.667>0.666667,对吗

你不能认为三位小数中的6/9是0.666,因为这不是与6/9最接近的三位小数


精度越低并不意味着数量越少。为什么你会期望相反的结果?唯一给定的是,双精度会更接近所需的值。它可能越小,也可能越大。@heshameraqi:答案(尤其是Kenny的答案)我相信你会从阅读中受益:假设你在计算3位小数和6位小数的1/9,对吧?现在假设你在计算6/9,对吧?你不能认为3位小数的6/9是
0.666,因为这是不是最接近6/9的3位小数!精确答案…!逻辑解释。你认为斯文的答案如何?换句话说,
0.2d>0.2f
@ratchetfreak…或不…取决于语言是否实现了IEEE 754,在哪个平台上运行…@HeshamERAQI两个答案都是正确的-我想这一个更容易理解为什么这种情况会发生。不过,对于这两种解释来说,关键是要考虑结果在截止点处的舍入方式。正如其他评论所说,FP表示的事实标准IEEE754是这样做的,但理论上可能存在只截断而不是舍入的FP实现。但这将取决于实现。我怀疑您的结果是针对IEEE
double
float
,因为这是目前最常用的,但在IBM或Unisys大型机上可能会得到不同的结果。@JamesKanze:这是在x86机器上。Python使用本机浮点操作,x86实现(或多或少)符合IEEE-754。这或多或少是我假设的(至少是IEEE-745):我认为几乎所有实现Python的机器都使用IEEE-754。我的观点是,在另一个体系结构上对应的值可能不同(比如一些不使用IEEE的大型机)。更好地描述您试图解决的问题
#include <iostream>
#include <cmath>

void foo(double x, double y)
{
  if (std::cos(x) != std::cos(y)) {
    std::cout << "Huh?!?\n";  //← you might end up here when x == y!!
  }
}

int main()
{
  foo(1.0, 1.0);
  return 0;
}
#include <stdio.h>
#include <float.h>

int main()
{
     double d = 0.1;
     float f = 0.1f;
     printf("%f\n", (f > d));

     return 0;
}