gpt4 book ai didi

delphi - 简单的 float 会失去精度

转载 作者:行者123 更新时间:2023-12-03 15:03:47 26 4
gpt4 key购买 nike

我正在使用 Delphi XE2 Update 3。即使是最简单的 float (例如 3.7)也存在精度问题。给定此代码(32 位控制台应用程序):

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses System.SysUtils;

var s: Single; d: Double; x: Extended;
begin
Write('Size of Single ----- '); Writeln(SizeOf(Single));
Write('Size of Double ----- '); Writeln(SizeOf(Double));
Write('Size of Extended --- '); Writeln(SizeOf(Extended)); Writeln;

s := 3.7; d := 3.7; x := 3.7;

Write('"s" is '); Writeln(s);
Write('"d" is '); Writeln(d);
Write('"x" is '); Writeln(x); Writeln;

Writeln('Single Comparison');
Write('"s > 3.7" is '); Writeln(s > 3.7);
Write('"s = 3.7" is '); Writeln(s = 3.7);
Write('"s < 3.7" is '); Writeln(s < 3.7); Writeln;

Writeln('Double Comparison');
Write('"d > 3.7" is '); Writeln(d > 3.7);
Write('"d = 3.7" is '); Writeln(d = 3.7);
Write('"d < 3.7" is '); Writeln(d < 3.7); Writeln;

Writeln('Extended Comparison');
Write('"x > 3.7" is '); Writeln(x > 3.7);
Write('"x = 3.7" is '); Writeln(x = 3.7);
Write('"x < 3.7" is '); Writeln(x < 3.7); Readln;
end.

我得到这个输出:

Size of Single  -----  4
Size of Double ----- 8
Size of Extended --- 10

"s" is 3.70000004768372E+0000
"d" is 3.70000000000000E+0000
"x" is 3.70000000000000E+0000

Single Comparison
"s > 3.7" is TRUE
"s = 3.7" is FALSE
"s < 3.7" is FALSE

Double Comparison
"d > 3.7" is TRUE
"d = 3.7" is FALSE
"d < 3.7" is FALSE

Extended Comparison
"x > 3.7" is FALSE
"x = 3.7" is TRUE
"x < 3.7" is FALSE

您可以看到 extend 是唯一正确计算的类型。我认为只有在使用像 3.14159265358979323846 这样的复杂 float 时,精度才是一个问题,而不是像 3.7 这样简单的东西。使用 single 时的问题是有道理的。但为什么 double 不起作用呢?

最佳答案

必读:What Every Computer Scientist Should Know About Floating-Point Arithmetic ,大卫·戈德堡。

问题不在于精度。相反,问题是代表性问题之一。首先,让我们回顾一下 float 用于表示实数。实数的数量是无限的。当然,对于整数也可以这样说。但这里的区别在于,在特定范围内,整数的数量是有限的,而实数的数量是无限的。确实如此originally shown by Cantor ,任何有限的实数区间都包含不可数的实值。

很明显,我们无法在有限机器上表示所有实数。那么,我们可以代表哪些数字呢?嗯,这取决于数据类型。 Delphi float 据类型使用二进制表示。单精度(32 位)和 double (64 位)类型符合 IEEE-754 标准。扩展(80 位)类型是 Intel 特定类型。在二进制浮点中,可表示的数字具有 k2n 的形式,其中 k 和 n 是整数。请注意,我并不是声称这种形式的所有数字都是可表示的。这是不可能的,因为这样的数字有无数个。相反,我的观点是所有可表示的数字都是这种形式。

可表示的二进制 float 的一些示例包括:1、0.5、0.25、0.75、1.25、0.125、0.375。您的值 3.7 无法表示为二进制浮点值。

对于您的代码而言,这意味着它没有执行您期望的操作。您希望与值 3.7 进行比较。但相反,您正在与最接近的精确表示值 3.7 进行比较。作为实现细节的问题,这个最接近的精确可表示值是在扩展精度的情况下的。这就是为什么使用扩展的版本看起来符合您的预期。但是,不要认为这意味着变量 x 等于 3.7。事实上,它等于最接近的可表示扩展精度值 3.7。

罗布·肯尼迪的most useful website可以向您显示与特定数字最接近的可表示值。对于 3.7,这些是:

3.7 = + 3.70000 00000 00000 00004 33680 86899 42017 73602 98112 03479 76684 57031 253.7 = + 3.70000 00000 00000 17763 56839 40025 04646 77810 66894 531253.7 = + 3.70000 00476 83715 82031 25

这些按扩展、双、单的顺序呈现。换句话说,这些分别是变量 xds 的值。

如果您查看这些值,并将它们与最接近的扩展值 3.7 进行比较,您就会明白为什么您的程序会产生这样的输出。这里的单精度值和 double 值都大于扩展值。这就是你的程序告诉你的。

我不想就如何比较浮点值提出任何笼统的建议。做到这一点的最佳方法始终非常关键地取决于具体问题。无法给出有用的笼统建议。

关于delphi - 简单的 float 会失去精度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23667061/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com