C#浮点数转换为十进制数

23

有没有一种聪明的方法将这样的浮点数转换:

float f = 711989.98f;

如何将一个数字转换为十进制(或double类型),而不会丢失精度?

我已尝试过:

decimal d = (decimal)f;
decimal d1 = (decimal)(Math.Round(f,2));
decimal d2 = Convert.ToDecimal(f);

更多细节: 我正在与一个旧的 Web 服务进行接口交互,该服务发送一个巨大的对象,其中一些字段为浮点数。当我将其转换为十进制时,崩溃了...不再有分钱! - Adrian4B
如果这是从网络服务传输的数据,那么它可能是XML格式,这意味着没有浮点数或小数 - 只有字符串。请查看这些字符串何时被转换为“内部”格式。 - mfeingold
5个回答

18

太晚了,第8位数字已经在编译器中丢失。浮点类型只能存储7个有效数字。你需要重写代码,使用double或decimal赋值来解决问题。


我已经将映射对象上的字段类型从float更改为decimal,并解决了反序列化过程中出现的转换问题。 - Adrian4B

6

这可能是编译器问题,因为似乎一个有效的浮点数应该能够直接转换为十进制。但是如果直接转换,它将失去精度。 将125.609375从浮点数转换为十进制将会失去精度。 然而,将其从浮点数转换为双精度,然后从双精度转换为十进制将保留精度。

    float float_val = 125.609375f;

    decimal bad_decimal_val = (decimal)float_val;   //125.6094

    double double_val = (double)float_val;
    decimal good_decimal_val = (decimal)double_val;

2
将浮点数转换为双精度浮点数并不会自动添加丢失的小数位。只需使用没有结尾处的 'f' 的浮点字面量(这些是双精度浮点数),或者使用十进制字面量,如 125.609375M。 - Christoph Rackwitz

2
你试过了吗?
decimal.TryParse()

http://forums.asp.net/t/1161880.aspx

浮点数(float/double)和十进制数(decimal)之间没有隐式转换。隐式数字转换始终保证不会丢失精度或大小,并且不会引发异常。

1
隐式转换不能保证不会丢失精度。将 9007199791611905 转换为 double 将产生 9007199791611904。直接转换为 float 将产生 9007200328482816。先转换为 double,然后再转换为 float 将产生 9007199254740992(比直接转换为 float 的误差更大)。此外,虽然编译器允许从 float 隐式转换为 double,但这种转换比从 double 转换为 float 更容易出错,尽管后者是不允许的,但应该允许。 - supercat
1
@supercat 显然,您可以无损地将 float 转换为 double。但是,将 double 转换为 float 可能会引入错误,具体取决于所涉及的特定 double 值。 - Drew Noakes
@DrewNoakes:如果一个人使用迭代计算来计算一个对象的位置,并使用接受float类型的图形例程来绘制它,那么将其转换为float将会减少精度,即使保留精度也通常是无用的;减少精度几乎肯定符合程序员意图。相比之下,如果某些代码例如将intlong除以float并将结果存储在double中,则除非程序员明确地将除法结果转换为float,否则我不会认为程序员... - supercat
实际上,预期除法应该只使用float精度。给定int x = 16777217; float y = 1.0f;,你认为编写double z = x / y;的程序员更可能期望z是16777216.0还是16777217.0?同样地,即使给定float one = 1.0f, ten = 10.0f; double d = one / ten;,你认为程序员更可能希望d接收值0.1f还是0.1? - supercat
@supercat,我理解你的观点。我来到这个问题是为了寻找有关从float/double转换为decimal时精度损失的信息(我正在考虑在反序列化器中允许此转换,以便模式可以以这种方式演变),因此主要关注单个转换期间的精度损失。对于这一点,我的评论是正确的。您的观点很有趣和有效,但我知道并避免通过仔细选择浮点类型而避免的陷阱。我对十进制数不太熟悉,特别是与从浮点数进行转换相关的内容。 - Drew Noakes
显示剩余2条评论

2

你在写711989.98f时就失去了精度。

711989.98是十进制数。在末尾加上f,你要求编译器将其转换为浮点数。这种转换无法在不损失精度的情况下完成。

你可能想要的是十进制数d = 711989.98m。这样就不会失去精度。


1
你的例子只使用了double,对吧?但是对于不同的数字仍然可能失去精度。只需在末尾加上“m”,并将字面值设为十进制即可开始。 - Carl G

0

试一下这个

float y = 20;

decimal x = Convert.ToDecimal(y/100);

print("test: " + x);

请阅读如何撰写好的答案?。虽然这个代码块可能回答了OP的问题,但如果您解释一下这段代码与问题中的代码有何不同,您做出了哪些更改,为什么要进行更改以及为什么这样解决问题而不会引入其他问题,那么这个答案将会更加有用。 - Saeed Zhiany

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