簡體   English   中英

為什么C#允許* Long隱式*從Long轉換為Float,這可能會失去精度?

[英]Why does C# allow an *implicit* conversion from Long to Float, when this could lose precision?

一個類似的問題Long in Float,為什么? 這里沒有回答我在尋找的東西。

C#標准允許從long到float的隱式轉換。 但任何長於2 ^ 24的長度在表示為浮動時必然會失去其“價值”。 C#標准清楚地表明,長期浮動轉換可能會失去“精確度”,但永遠不會失去“幅度”。

我的問題是
  1. 關於積分類型,“精確”和“幅度”的含義。 與實數不同,數字n與數字n + 1完全不同,其中3.333333和3.333329可能被認為足夠接近計算(即取決於程序員想要的精度)
  2. 不允許隱式轉換從long到浮動邀請到微妙的錯誤,因為它可能導致長期“默默地”失去價值(作為一個C#程序員,我習慣於編譯器在防范這些問題方面做得非常出色)

那么C#語言設計團隊允許這種轉換是隱含的理由是什么呢? 我在這里失蹤的是什么證明從長期到浮動的隱性轉換是正確的?

這是一個很好的問題。 實際上你可以概括這個問題,因為隱含轉換存在同樣的問題:

  • int to float
  • uint float
  • long float你要問的
  • ulong float
  • longdouble
  • ulong double

實際上, 所有整數類型 (甚至是char !!)都有一個隱式轉換為floatdouble ; 但是,只有上面列出的轉換會導致精度損失。 另一個有趣的事情是,在解釋“為什么沒有從十進制到雙精度的隱式轉換”時,C#語言規范有一個自相矛盾的參數:

十進制類型具有更高的精度,但比浮點類型的范圍更小。 因此,從浮點類型到十進制的轉換可能會產生溢出異常, 從十進制到浮點類型的轉換可能會導致精度損失。 由於這些原因,浮點類型和十進制之間不存在隱式轉換 ,並且沒有顯式轉換,不可能在同一表達式中混合浮點和十進制操作數。

我認為,“為什么做出這個決定”的問題最好由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;

長期失去價值的問題只有在有可能無聲地獲得轉換后的長期時才會到達。

謝謝大家幫助我增進了解。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM