为什么C#允许* Long隐式*从Long转换为Float,这可能会失去精度?

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

C#标准允许从long到float的隐式转换。 但任何长于2 ^ 24的长度在表示为浮动时必然会失去其“价值”。 C#标准清楚地表明,长期浮动转换可能会失去“精确度”但永远不会失去“幅度”。

我的问题是

  1. 关于积分类型,“精确”和“幅度”的含义。 数字n与数字n + 1完全不同,与实数不同,其中3.333333和3.333329可能被认为足够接近计算(即取决于程序员想要的精度)
  2. 不允许隐式转换从long到浮动邀请到微妙的错误,因为它可能导致长期“默默地”失去价值(作为一个C#程序员,我习惯于编译器在防范这些问题方面做得非常出色)

那么C#语言设计团队允许这种转换是隐含的理由是什么呢? 我在这里失踪的是什么certificate从长期到浮动的隐性转换是正确的?

通常, 浮点数并不完全代表许多数字。 就其本质而言,它们是不精确的并且容易出现精确误差。 它真的没有增加价值来警告你浮点的情况总是如此。

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

  • int to float
  • uint float
  • longfloat你问的是
  • ulong float
  • longdouble
  • ulong double

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

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

我认为,“为什么做出这个决定”的问题最好由像Eric Lippert这样的人来回答。 我最好的猜测……这是语言设计者没有任何强烈的论据去做某种方式的事情之一,所以他们选择(他们认为的)更好的替代方案,尽管这是有争议的。 在他们的辩护中,当你将一个大long转换为float ,你的精度会松散,但你仍然得到浮点世界中这个数字的最佳表示 。 它就像转换一个intbyte ,可能存在溢出(整数值可能超出byte可以表示的范围)并且得到一个不相关/错误的数字。 但是,在我看来,如果它们没有进行导致精度损失的其他转换,那么从没有从decimal到浮点的隐式转换会更加一致。

  1. 关于积分类型,“精确”和“幅度”的含义。 数字n与数字n + 1完全不同,与实数不同,其中3.333333和3.333329可能被认为足够接近计算(即取决于程序员想要的精度)

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

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

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

使用double和float,您可以准确表示以下值:(int = 32位,long = 64位,均为signed 🙂

int – > float -2 ^ 24 – 2 ^ 24

int – >加倍所有值

long – > float -2 ^ 24 – 2 ^ 24

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

是不是允许隐式转换从long到浮动邀请到微妙的错误,因为它可以导致长期“默默地”失去价值(作为一个C#程序员,我习惯于编译器>在防范这些问题方面做得非常出色)

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

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

max long值可以放入float

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

即使long64bit Integer类型而float32bit ,但计算机处理float's方式与long's不同。 但是对于float ,以牺牲精度为代价实现了更大的范围。

long具有比float高得多的精度,但是与long 10 ^ 18相比,浮子具有更高的数量级10 ^ 38。

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

Double -15-16位(64位)

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

进一步思考,似乎所有三个答案(更多/更少指向相同的事情)能够正确地解释它的’为什么’部分。

  1. float和long都是数值类型
  2. 浮动范围大到足以保持长距离

我认为上述两个标准足以说明长期浮动转换应该是隐含的。

由于float是单精度,因此无法准确表示long的所有值。 因此,他们将其作为标准中的事实陈述。 long to float转换是“安全的”,因为生成的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; 

长期失去价值的问题只有在有可能无声地获得转换后的长期时才会到达。

谢谢大家帮助我增进了解。