- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 Delphi 2010 中遇到了舍入奇怪的问题,其中一些数字在 roundto 中向下舍入,但在 formatfloat 中向上舍入。
我完全意识到十进制数的二进制表示有时会给出误导性的结果,但在这种情况下,我希望 formatfloat 和 roundto 给出相同的结果。
我还看到过一些建议,认为应该使用“Currency”来实现这种目的,但正如您在下面看到的,Currency 和 Double 给出了相同的结果。
program testrounding;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,Math;
var d:Double;
c:Currency;
begin
d:=534.50;
c:=534.50;
writeln('Format: ' +formatfloat('0',d));
writeln('Roundto: '+formatfloat('0',roundto(d,0)));
writeln('C Format: ' +formatfloat('0',c));
writeln('C Roundto: '+formatfloat('0',roundto(c,0)));
readln;
end.
结果如下:
Format: 535
Roundto: 534
C Format: 535
C Roundto: 534
我看过Why is the result of RoundTo(87.285, -2) => 87.28并且建议的补救措施似乎并不适用。
最佳答案
首先,我们可以从问题中删除 Currency
,因为您使用的两个函数没有 Currency
重载。该值将转换为 IEEE754 浮点值,然后遵循与 Double
代码相同的路径。
让我们首先看一下RoundTo
。使用调试器或附加的 Writeln
可以快速检查 RoundTo(d,0) = 534
。这是为什么?
嗯,documentation对于 RoundTo
说:
Rounds a floating-point value to a specified digit or power of ten using "Banker's rounding".
事实上,在RoundTo
的实现中,我们看到舍入模式在恢复到其原始值之前暂时切换为TRoundingMode.rmNearest
。舍入模式仅适用于值正好是两个整数之间的一半时。我们这里的情况正是如此。
因此银行家四舍五入适用。这意味着当该值正好是两个整数之间的一半时,舍入算法会选择相邻的偶数整数。
因此,RoundTo(534.5,0) = 534
是有意义的,同样您可以检查 RoundTo(535.5,0) = 536
。
理解FormatFloat
是完全不同的事情。坦率地说,它的行为有些不透明。它在不同平台的代码中执行不同的临时舍入。例如,它在 32 位 Windows 上是汇编程序,但在 64 位 Windows 上是 Pascal。总体方法似乎是获取浮点值的尾数,将其转换为整数,将其转换为文本数字,然后根据这些文本数字执行舍入。执行舍入时不会考虑当前的舍入模式,并且该算法似乎实现了 round half away from zero policy 。然而,即使如此,也不能针对所有可能的浮点值稳健地实现。它对于您的值可以正确工作,但对于尾数中包含更多数字的值,算法会崩溃。
事实上,众所周知,用于在浮点值和文本之间进行转换的 Delphi RTL 例程从根本上被设计破坏了。 Delphi RTL 中没有任何例程可以正确地从文本转换为浮点型,或从浮点型转换为文本。事实上,我最近实现了自己的转换例程,它基于其他语言运行时使用的现有开源代码正确地执行了此操作。总有一天我会抽出时间发布此代码以供其他人使用。
我不确定您的确切需求是什么,但如果您希望对舍入进行一些控制,那么如果您负责舍入,则可以这样做。虽然 RoundTo
始终使用 Banker 舍入模式,但您也可以使用 Round
它使用当前舍入模式。这将允许您使用您选择的舍入算法(通过调用SetRoundMode
)执行舍入,然后您可以将舍入值转换为文本。这就是关键。将值保留为算术类型,执行舍入,并且仅在应用正确舍入后的最后一刻才转换为文本。
关于Delphi Roundto 和 FormatFloat 不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57193437/
在此代码中: FormatFloat('0.##########',XX.AsFloat) 如果数据库中的值XX是12.12345,它会返回什么值? #的个数超过小数点后5位,会进行四舍五入吗? 我找
我有一个应用程序,用户可以在其中设置值的显示方式。用户输入格式化字符串,组件使用 FormatFloat 来显示该值。 但现在我们正在使用一个新的第三方组件,它使用 Format 函数格式化值,当然,
我在 Delphi 2010 中遇到了舍入奇怪的问题,其中一些数字在 roundto 中向下舍入,但在 formatfloat 中向上舍入。 我完全意识到十进制数的二进制表示有时会给出误导性的结果,但
我只是想使用类型开关来处理时间、float32 和 float64。它适用于时间和 float64s,但 strconv.FormatFloat(val, 'f', -1, 32) 一直告诉我不能使用
这个问题在这里已经有了答案: Is floating point math broken? (31 个回答) 3年前关闭。 尝试使用函数 FormatFloat 将 double 值四舍五入到小数点后
我正在尝试使用以下脚本将货币格式的值打印到报告上的 TfrxMemoView: procedure txCreditLimitOnBeforePrint(Sender: TfrxComponent);
我是一名优秀的程序员,十分优秀!