22

一个类似的问题Long in Float,为什么?这里没有回答我正在寻找的东西。

C# 标准允许从 long 到 float 的隐式转换。但是当表示为浮点数时,任何大于 2^24 的 long 都必然会失去其“价值”。C# 标准明确指出 long to float 转换可能会失去“精度”,但永远不会失去“幅度”。

我的问题是
  1. 关于整数类型,“精度”和“量级”是什么意思。数字 n 与数字 n+1 是否完全不同,这与实数不同,其中 3.333333 和 3.333329 可能被认为足够接近以进行计算(即取决于程序员想要的精度)
  2. 不允许从 long 隐式转换到浮动对细微错误的邀请,因为它可能导致 long '默默地'失去价值(作为 C# 程序员,我习惯于编译器在保护我免受此类问题方面做得很好)

那么 C# 语言设计团队允许这种隐式转换的基本原理是什么?我在这里缺少什么来证明从 long 到 float 的隐式转换是合理的?

4

5 回答 5

13

这是一个很好的问题。实际上你可以概括这个问题,因为同样的问题存在于隐式转换:

  • intfloat
  • uintfloat
  • longfloat你要问的
  • ulongfloat
  • longdouble
  • ulongdouble.

事实上,所有整数类型(甚至char!!)都隐式转换为floatand double; 但是,只有上面列出的转换会导致精度损失。另一个需要注意的有趣的事情是,C# 语言规范在解释“为什么没有从十进制到双精度的隐式转换”时有一个自相矛盾的论点:

十进制类型比浮点类型具有更高的精度但范围更小。因此,从浮点类型到十进制的转换可能会产生溢出异常,而从十进制到浮点类型的转换可能会导致精度损失。由于这些原因,浮点类型和小数之间不存在隐式转换,并且如果没有显式转换,就不可能在同一个表达式中混合浮点和小数操作数。

我认为“为什么做出这个决定”的问题最好由像 Eric Lippert 这样的人来回答。我最好的猜测......这是语言设计者没有任何强有力的论据来选择一种方式的事情之一,所以他们选择(他们认为是)更好的替代方案,尽管这是有争议的. 在他们的辩护中,当您将大数转换为 时longfloat您的精度会降低,但您仍然会得到浮点世界中该数字的最佳表示形式。这与将 an 转换intbyte可能存在溢出的地方(整数值可能超出 a 的范围)完全不同。byte可以代表),你得到一个不相关/错误的数字。decimal但是,在我看来,如果它们也没有导致精度损失的其他转换,它会更符合没有从浮点到浮点的隐式转换。

于 2012-06-25T15:09:34.520 回答
8

一般来说,浮点数不能准确地表示很多数字。就其性质而言,它们是不精确的并且容易出现精度误差。它确实没有增加价值来警告您浮点的情况。

于 2012-06-25T11:14:24.937 回答
2
  1. 关于整数类型,“精度”和“量级”是什么意思。数字 n 与数字 n+1 是否完全不同,这与实数不同,其中 3.333333 和 3.333329 可能被认为足够接近以进行计算(即取决于程序员想要的精度)

“精度”定义了一个数字可以携带的位数。如果您(为方便起见)将它们编码为 BCD,则一个字节只能携带 2 个十进制数字。假设您有 2 个字节可用。您可以使用它们以整数格式对数字 0-9999 进行编码,或者您可以定义最后一位表示十进制指数的格式。

您可以编码然后 0-999 * (10^0 - 10^9)

您现在可以将数字编码为 999 000 000 000,而不是从 0-9999 编码数字。但是,如果您将 9999 从整数格式转换为新格式,则只能得到 9990。您已经获得了可能数字的范围(您的幅度),但你失去了精度。

使用双精度和浮点数,您可以得到以下可以精确表示的值:(int = 32 位,long = 64 位,均带符号:)

整数 -> 浮点数 -2^24 - 2^24

int -> 将所有值加倍

长 -> 浮动 -2^24 - 2^24

长 -> 双 -2^53 - 2^53

不允许从 long 隐式转换到浮动对细微错误的邀请,因为它 > 可能导致 long '默默地'失去价值(作为 C# 程序员,我习惯于编译器 > 在保护我免受此类问题方面做得很好)

是的,它引入了无声的错误。如果您希望编译器可以帮助您解决这些问题,请忘记它。你只能靠自己。我不知道任何警告不要失去精确度的语言。

一个这样的错误: 阿丽亚娜火箭......

于 2012-06-25T10:09:38.577 回答
1

最大值long可以放入floatas

float.MaxValue ~= 3.402823+e38 
long.MaxValue ~= 9.223372+e18 

尽管long是一个64bit Integer类型并且float32bit,但是计算机处理的方式float's是不同的long's。但float更大的范围是以牺牲精度为代价的。

long具有比10 ^ 18更高的精度,float但浮点数具有更高的数量级 10 ^ 38 。long

我不认为他们犯了一个错误,允许隐式转换longfloatasfloat仍然精确到 7 位。因此,如果有人需要更高的精度,他们总是可以使用double或小数`

Double-15-16 位(64 位)

Decimal-28-29 位有效数字(128 位)

于 2012-06-25T06:31:44.213 回答
1

进一步思考,似乎所有三个答案(或多/少指向同一件事)都能够正确解释其中的“为什么”部分。

  1. float 和 long 都是数字类型
  2. 浮动的范围足够大以容纳多头的范围

我认为以上两个标准足以表明 long to float 转换应该是隐式的。

由于 float 是单精度的,它不能准确地表示 long 的所有值。因此,他们将其作为事实陈述包含在标准中。long 到 float 的转换是“安全的”,因为生成的 float 可以很容易地表示 long 值,但会失去精度。

进一步的 float 到 long 的转换不是隐含的(因为 float 的范围远远大于 long 可以容纳的范围),这确保了这样的事情是不允许的

long lng = 16777217;
float flt = lng; //loses precision here
long lng2 = flt; //if permitted, would be 16777216 or 2^24
bool eq = lng == lng2;

只有在可以默默取回转换后的多头时,才会出现多头失去其价值的问题。

感谢大家帮助我加深理解。

于 2012-06-25T11:38:22.853 回答