如何在Delphi中将浮点数转换为最多有2位小数的字符串

3

在Delphi7中,如何将浮点数转换为最多2个小数位的字符串?

我尝试使用以下方法:

 FloatToStrF(Query.FieldByName('Quantity').AsFloat, ffGeneral, 18, 2, FS);

但是有时候会返回超过2位小数,即结果为:15.60000009


2
Format('%3.2f', [yourFloatValue]) 是怎么样的呢? - Rudy Velthuis
1
或者 str(myfloat:18:2,mystring) - gammatester
3个回答

4

请使用ffFixed代替ffGeneral

ffGeneral忽略Decimal参数。

当您使用ffGeneral时,18表示您想要18个有效的小数位。然后,该程序将以最短的方式表达该数字,必要时使用科学计数法。 2将被忽略。

当您使用ffFixed时,您表示您希望小数点后有2位。

如果您想知道为什么有时会得到看起来不精确的值,可以在本网站和其他网站上找到很多解释浮点数如何工作的内容。

在本例中,AsFloat返回一个double,就像(大多数)其他浮点格式一样,它以二进制存储其值。 就像1/3无法用有限的数字写成十进制一样,15.6也无法用有限的位数在二进制中表示。 系统选择可以存储在double中的最接近的可能值。 精确的值以十进制表示为:

15.5999999999999996447286321199499070644378662109375

如果您要求16位精度,则该值将四舍五入为15.6。 但是您要求18位数字,因此得到15.5999999999999996。


这对您有帮助吗? - David Dubois
因为问题指定“最大2位小数”,所以被点踩。此答案始终给出2位小数。 - Dave Nottage

1
如果您的意思是您所写的内容实际上只需要保留两位小数(最多两位小数),而不是总是保留两位小数,那么评论中的这两段代码将无法满足您的需求(它们将返回一个始终保留两位小数的字符串,即“1”将被返回为“1.00”(或者根据您的小数点格式为“1,00”)。
如果您真正想要一个最多保留两位小数的选项,您需要对返回的字符串进行一些后处理。
FUNCTION FloatToStrMaxDecimals(F : Extended ; MaxDecimals : BYTE) : STRING;
  BEGIN
    Result:=Format('%.'+IntToStr(MaxDecimals)+'f',[F]);
    WHILE Result[LENGTH(Result)]='0' DO DELETE(Result,LENGTH(Result),1);
    IF Result[LENGTH(Result)] IN ['.',','] THEN DELETE(Result,LENGTH(Result),1)
  END;

另一种(可能更快的)实现方式可以是:

FUNCTION FloatToStrMaxDecimals(F : Extended ; MaxDecimals : BYTE) : STRING;
  BEGIN
    Result:=Format('%.'+IntToStr(MaxDecimals)+'f',[F]);
    WHILE Result[LENGTH(Result)]='0' DO SetLength(Result,PRED(LENGTH(Result)));
    IF Result[LENGTH(Result)] IN ['.',','] THEN SetLength(Result,PRED(LENGTH(Result)))
  END;

此函数将返回一个浮点数,最多指定小数位数。例如,MAX为2的一半将返回“0.5”,MAX为2的三分之一将返回“0.33”,MAX为2的两个三分之一将返回“0.67”。MAX为2的TEN将返回“10”。

最终的IF语句应该真正测试适当的小数点,但我认为除了句号或逗号以外,不可能有其他值,并且如果这些字符中的一个在从末尾剥离所有零后留下作为最后一个字符,则它必须是小数点。

还要注意,此代码假定字符串使用1作为第一个字符进行索引,就像在Delphi 7中总是这样一样。如果您需要此代码用于更新版本的Delphi移动编译器,则需要更新代码。我会把这个练习留给读者 :-).


1
  1. 为什么不把 MaxDecimals 作为开放数组的参数,而是将其包含在字符串中?
  2. 在循环中调用 Delete 操作会变得过慢。最好找到要截断的位置,一次性进行截断。
- Andreas Rejbrand
1
@HeartWare:使用更好的算法或函数并不是“过早”的优化。你首先编写一个能够工作但速度较慢的方法,然后开始优化和删除过于缓慢的代码,直到你拥有了一些可以向主要公众展示的东西。哦,而且最好使用Format('%.*f', [MaxDecimals, F]);。这样更容易阅读。 - Rudy Velthuis
除非你能证明它确实是一个“更好的算法”,否则,在我看来,这是过早的。此外,“更容易阅读”是一种口味问题。对我来说,它并不容易阅读。你的情况可能不同。可读性比速度更重要,除非在现实世界中速度的提高是显著的(而不仅仅是在“现在我调用这个函数一亿次来证明在这种情况下,它快了X毫秒”)。 - HeartWare
1
在我看来,是的。可读性是可以衡量的,顺便说一句。使用标准编码约定比使用自己的编码方式始终会使代码更易读。 - Rudy Velthuis
1
使用标准编码规范比使用自己的规范更易读。除此之外,“标准编码规范”随着时间的推移也在不断变化。我只是遵循了一个早于你所遵循的规范而已。 - HeartWare
显示剩余7条评论

0
我在我的应用程序中使用了这个函数:
function sclCurrencyND(Const F: Currency; GlobalDegit: word = 2): Currency;
var R: Real; Fact: Currency;
begin
  Fact:= power(10, GlobalDegit);
  Result:= int(F*Fact)/Fact;
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接