Delphi FormatFloat不同的行为(变量和数据集)
我发现Delphi的FormatFloat函数有一个奇怪的行为。让我展示一下案例研究 要转换的值:129809.495Delphi FormatFloat不同的行为(变量和数据集),delphi,ado,delphi-xe5,unidac,Delphi,Ado,Delphi Xe5,Unidac,我发现Delphi的FormatFloat函数有一个奇怪的行为。让我展示一下案例研究 要转换的值:129809.495 所需格式化输出:129809.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:
所需格式化输出:129809.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和Firebird 1.5测试这种行为。使用的组件是ADO组件和UniDAC组件(由DevArt提供),它们都具有相同的行为 我尝试过这样做:
- FormatFloat(',0.00',Dataset.Field[0].AsFloat)李>
- FormatFloat(',0.00',StrToFloat(Dataset.Field[0].AsString))李>
- val:=数据集。字段[0]。AsFloat;格式浮点(',0.00',val)李>
- str:=数据集。字段[0]。关联字符串;FormatFloat(',0.00',StrToFloat(str))李>
- val:=StrToFloat(Dataset.Field[0].AsString);格式浮点(',0.00',val)李>
val := StrToFloat(Dataset.Field[0].AsString);
FormatFloat(',0.00', val);
有人能解决这种行为吗?因为强制转换StrToFloat,然后重新格式化变量/输出,工作量太大了。这种变通方法不能应用于使用FormatFloat的第三方组件
谢谢你的帮助。谢谢在这里制作一个我喜欢的单元:
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));
对于我的函数,结果是val 129809.49,因为在从单变量转换为扩展变量后,传递给函数的变量是129809.4921875。因此,对于调试而言,写入每个函数调用的日志文件可能是个好主意。这似乎与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不能像预期的那样保持要舍入的正确值,而extended更合适。此外,当值曾经以双精度格式存储时,简单地将其转换为extended(FormatFloat就是这种情况)并不能解决舍入错误。使用现有函数名是一种非常糟糕的做法。另外,您没有使用
格式
参数…不是混合而是过度使用。这是我找到的最快最简单的解决方案。如果用户愿意,他可以用Format参数覆盖函数。考虑到这样的函数名会发生什么,你永远不会称它为最快和最简单的函数(我知道你用这些最高级的词来描述代码)。如果您真的想解决OP的问题,您最好使用t字段的类帮助程序。感谢您的回答,但我恐怕无法将此用于DevExpress的TcxCurrencyEdit组件及其显示格式设置。我先试试这个字段的数据类型是什么?@uwerabe Firebird 1.5的数据类型是“双精度”,SQLServerWow的数据类型是“金钱”,现在我知道了。但是如何将Dataset.Field.AsFloat转换为extended?正如其中所述。AsFloat返回double:(进行了更多的研究,发现因此我需要执行Field.AsCurrency以产生正确的精度舍入