我发现了Delphi的FormatFloat函数的奇怪行为。让我展示案例研究。
要转换的价值:129809.495
格式化输出所需:129,809.50
案例1:从字符串转换
var str: string;
str := '129809.495';
str := FormatFloat(',0.00', StrToFloat(str));
// output is 129,809.50 = CORRECT
案例2:从双变量转换
var number: double;
str: string;
val := 129809.495;
str := FormatFloat(',0.00', val);
// output is 129,809.50 = CORRECT
案例3:从数据集的字段转换
*it's too complex to write here, let me just explain*
Basically the formatted output of FormatFloat(',0.00', Dataset.Field[0].AsFloat);
always resulted in 129,809.49 == WRONG
我一直在使用SQL Server 2008& amp ;; Firebird 1.5。
使用的组件是ADO组件和UniDAC组件(由DevArt提供),并且都具有相同的行为。
我试过这些:
但是所有导致同样错误的转换.49而不是.50
有效的方法是
val := StrToFloat(Dataset.Field[0].AsString);
FormatFloat(',0.00', val);
有没有人有这种行为的解决方案?因为强制转换StrToFloat然后重新格式化变量/输出是太多的工作。此解决方法不能应用于使用FormatFloat
的第三方组件任何帮助表示赞赏。感谢
答案 0 :(得分:1)
看起来它与Double和Extended之间的某些精度差异有关。实际上我无法确认您对案例2的正确观察。也许是因为你将变量数声明为double,但是然后使用未知类型的变量val。
无论如何,以下代码
var
d: Double;
e: Extended;
begin
d := 129809.495;
e := 129809.495;
Writeln(FormatFloat(',0.00', d));
Writeln(FormatFloat(',0.00', e));
e := d;
Writeln(FormatFloat(',0.00', e));
e := 129809.495;
d := e;
Writeln(FormatFloat(',0.00', d));
end;
使用XE6编译的产生以下输出:
129,809.49
129,809.50
129,809.49
129,809.49
这导致得出结论:double不能保持正确的值以按预期舍入,而扩展更合适。此外,当值以double格式存储时,只需将其转换为扩展(即FormatFloat会发生这种情况)并不能解决舍入错误。
答案 1 :(得分:-1)
在这里创建一个单位MyUnit:
unit MyUnit;
interface
uses
System.SysUtils;
function FormatFloat(const Format: string; Value: Extended): string;
implementation
function FormatFloat(const Format: string; Value: Extended): string;
begin
Value := StrToFloat(Value.ToString);
Result:=System.SysUtils.FormatFloat(',0.00', Value);
end;
end.
并在Uses子句的最后位置 中插入 。对FormatFloat函数的任何调用都将调用您的函数。
顺便说一句,这种行为可能是四舍五入或准确度不足的结果。我试过这个:
var
val: Single;
begin
val:=129809.495;
ShowMessage(FormatFloat(',0.00', val));
我的函数和rseult是val 129809.49,因为从Single转换为Extended后传递给函数的变量是129809.4921875。因此,对于调试写入每个函数调用的日志文件可能是个好主意。