Ответ 1
Во-первых, важно помнить, что 0.6
нельзя точно представить как float
, однако его можно точно представить как double
(неточности арифметики с плавающей запятой хорошо документированы, если ее непонятно почему 0.6
нельзя точно представить как float, попробуйте эта ссылка)
Причина, по которой вы видите описанное выше поведение, сводится к компилятору - если вы посмотрите на скомпилированную сборку в рефлекторе, то что происходит здесь, это немного яснее:
( ОБНОВЛЕНИЕ. Я изменил код, чтобы он не использовал Console.WriteLine
, так как я понял, что компилятор выбрал для вас перегрузку, что смутило ситуацию)
// As written in source
var j = (double)(float)0.6;
var k = (double)0.6f;
var l = (double)(6/10f);
var m = (double)(float)(6/10f);
// Code as seen by Reflector
double j = 0.60000002384185791;
double k = 0.60000002384185791;
double l = 0.6;
double m = 0.6;
Почему компилятор решает скомпилировать этот особый путь вне меня (fyi, все это с отключенными оптимизациями)
Некоторые интересные другие случаи:
// Code
var a = 0.6;
var b = (double)0.6;
var c = 0.6f;
var d = (float)0.6;
var e = 6 / 10;
var f = 6 / (10f);
var g = (float)(6 / 10);
var h = 6 / 10f;
var i = (double)6 / 10;
// Prints out 0.60000002384185791
double n = (float)0.6;
double o = f;
// As seen by Reflector
double a = 0.6;
double b = 0.6;
float c = 0.6f;
float d = 0.6f;
int e = 0;
float f = 0.6f;
float g = 0f;
float h = 0.6f;
double i = 0.6;
double n = 0.60000002384185791;
double o = f;
Компилятор, похоже, делает вышеупомянутый трюк в нескольких особых случаях, почему он делает это только тогда, когда кастинг на двойник полностью выходит за рамки меня!
Остальное время, похоже, делает некоторые обманы для создания арифметики с плавающей запятой, похоже, работает там, где на самом деле это обычно не будет.