德尔福数学:为什么0.7 <0.70?

Al *_*l C 10 delphi math floating-point comparison types

如果我有变量a,b,类型为double的c,设c:= a/b,并给出a和b值为7和10,则c的值为0.7,寄存器小于0.70.

另一方面,如果变量都是类型扩展的,则c的值0.7不会注册为小于0.70.

这看起来很奇怪.我错过了哪些信息?

Ken*_*ssa 18

首先,需要注意的是Delphi中的float文字属于Extended类型.因此,当您将double与文字进行比较时,double可能首先"扩展"为Extended,然后进行比较.(编辑:仅在32位应用程序中才是这样.在64位应用程序中,Extended是别名Double)

在这里,将显示所有ShowMessage.

procedure DoSomething;
var
  A, B : Double;
begin
  A := 7/10;
  B := 0.7; //Here, we lower the precision of "0.7" to double

  //Here, A is expanded to Extended...  But it has already lost precision. This is (kind of) similar to doing Round(0.7) <> 0.7
  if A <> 0.7 then 
    ShowMessage('Weird');

  if A = B then //Here it would work correctly.
    ShowMessage('Ok...');

  //Still... the best way to go...
  if SameValue(A, 0.7, 0.0001) then
    ShowMessage('That will never fails you');
end;
Run Code Online (Sandbox Code Playgroud)

这里有一些文献给你

每个计算机科学家应该知道的浮点运算

  • 有关浮点运算的_the_规范链接的+1. (3认同)

Pas*_*uoq 11

0.7二进制浮点数学数字没有表示.你的陈述计算在c最近的double,根据你的说法,我没有检查,是略低于0.7.

显然,在扩展精度中,最接近的浮点数为0.7,略高于它.但仍然没有确切的代表0.7.二进制浮点中没有任何精度.

根据经验,任何非最后一个非零小数不是5的非整数都不能完全表示为二进制浮点数(反之亦然:0.05也不能完全表示).


dth*_*rpe 8

它与您正在使用的两种不同浮点类型中的精度位数有关,以及无论精度如何都无法准确表示大量数字的事实.(从纯粹的数学方面看:非理性数字超过有理数)

以2/3为例.它'不能用十进制表示.有4位有效数字,它表示为0.6667.有8位有效数字,当前为0.66666667.尾随7是综合反映,如果有空间保留它,下一个数字将> 5.

0.6667大于0.66666667,因此计算机将评估2/3(4位)> 2/3(8位).

双重和扩展变量中的.7 vs .70也是如此.

要避免此特定问题,请尝试在整个代码中使用相同的数字类型.一般使用浮点数时,有很多小事需要注意.最大的不是编写代码来比较两个浮点数是否相等 - 即使它们应该是相同的值,计算中有许多因素会使它们最终变得非常微小.您需要测试两个数字之间的差异是非常小的,而不是比较相等性.差异有多小取决于你和计算的性质,它通常被称为epsilon,取自微积分定理和证明.


Joh*_*mas 5

你错过了这件事.

特别参见" 准确性问题 "一章.另见Pascal的答案.为了在不使用Extended类型的情况下修复代码,必须添加Math单元并使用SameValue专门为此目的而构建的功能.

Epsilon在您的情况下使用SameValue时,请务必使用不同于0 的值.

例如:

var
  a, b, c: double;


begin
  a:=7; b:=10;
  c:=a/b;

  if SameValue(c, 0.70, 0.001) then
    ShowMessage('Ok')
  else
    ShowMessage('Wrong!');
end;
Run Code Online (Sandbox Code Playgroud)

HTH