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

时间:2012-06-25 05:42:26

标签: c# .net floating-point long-integer implicit-conversion

类似的问题Long in Float, why?在这里没有回答我要搜索的内容。

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

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

5 个答案:

答案 0 :(得分:11)

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

  • intfloat
  • uintfloat
  • longfloat(您询问的
  • ulongfloat
  • longdouble
  • ulongdouble

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

  

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

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

答案 1 :(得分:8)

通常,floating point numbers并不完全代表许多数字。就其性质而言,它们是不精确的并且容易出现精确错误。它确实没有增加值来警告你浮点数总是如此。

答案 2 :(得分:2)

  
      
  1. 关于积分类型,'精确'和'幅度'的含义。是不是   数字n完全不同于数字n + 1不同   实际数字3.333333和3.333329可能被认为是接近的   足以进行计算(即取决于程序员的精确度)   想)
  2.   

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

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

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

使用双精度浮点数和浮点数,您可以准确表示以下值: (int = 32位,long = 64位,都签名:)

int - >漂浮-2 ^ 24 - 2 ^ 24

int - >加倍所有值

长 - >漂浮-2 ^ 24 - 2 ^ 24

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

  

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

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

一个这样的错误: Ariane rocket...

答案 3 :(得分:1)

最大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。

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

Double - 15-16位(64位)

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

答案 4 :(得分:1)

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

  1. float和long都是数值类型
  2. 浮动范围足以容纳长距离
  3. 我认为上述两个标准足以说明长期浮动转换应该是隐含的。

    由于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;
    

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

    感谢所有人帮助我提高理解力。