Подтвердить что ты не робот

Почему С# допускает * неявное * преобразование от Long to Float, когда это может потерять точность?

Аналогичный вопрос Long in Float, почему? здесь не отвечает на то, что я ищу.

Стандарт С# позволяет неявное преобразование из long в float. Но любое длиннее 2 ^ 24, представленное в виде поплавка, обязательно потеряет свою "ценность". Стандарт С# ясно указывает, что долгое время плавающего преобразования может потерять "точность", но никогда не потеряет "величину".

Мои вопросы
  • В отношении интегральных типов подразумевается "точность" и "величина". Не является ли число n полностью отличным от числа n + 1, в отличие от действительных чисел, где 3.333333 и 3.333329 могут считаться достаточно близкими для вычисления (то есть в зависимости от того, чего хочет программист-программист).
  • Не позволяет неявное преобразование из long, чтобы плавать приглашение на тонкие ошибки, поскольку это может привести к длительной "бесшумной" утрате ценности (в качестве программиста на С# я привык к компилятору, который отлично справляется с защитой от таких проблем )

Итак, что могло бы послужить основанием для команды разработчиков языка С#, позволяющей это преобразование как неявное? Что мне здесь не хватает, что оправдывает неявное преобразование из long to float?

4b9b3361

Ответ 1

В общем, числа с плавающей запятой не представляют точно числа. По своей природе они неточны и подвержены ошибкам точности. Это действительно не повышает ценность, чтобы предупредить вас о том, что всегда происходит с плавающей точкой.

Ответ 2

Это хороший вопрос. На самом деле вы можете обобщить этот вопрос, поскольку такая же проблема существует для неявных преобразований:

  • int to float
  • uint to float
  • long до float (о котором вы спрашиваете)
  • ulong to float
  • long до double
  • ulong до double.

Фактически, все интегральные типы (и даже char!!) имеют неявное преобразование в float и double; однако только перечисленные выше преобразования приводят к потере точности. Еще одна интересная вещь, которую следует отметить, заключается в том, что спецификация языка С# имеет противоречивый аргумент при объяснении "почему нет неявного преобразования из десятичной в двойную":

Десятичный тип имеет большую точность, но меньший диапазон, чем типы с плавающей запятой. Таким образом, преобразования из типов с плавающей запятой в десятичные могут приводить к исключениям переполнения, и конверсии из десятичных чисел в типы с плавающей точкой могут привести к потере точности. По этим причинам не существует неявных преобразований между типами с плавающей запятой и десятичной, и без явных отбросов невозможно сопоставить числа с плавающей запятой и десятичные операнды в одном выражении.

Вопрос о том, "почему это решение было принято", можно было бы лучше всего ответить, например, Эрику Липперту. Моя догадка... это одна из тех вещей, где разработчики языка не имеют никаких сильных аргументов в пользу идти в одну сторону или другую сторону, поэтому они выбрали (как они думали), тем лучше альтернатив, хотя это спорно, В свою защиту, когда вы конвертируете большой long в float, вы теряете точность, но вы все равно получаете то, что является лучшим представлением этого числа в мире с плавающей точкой. Это не похоже на преобразование, скажем, int в byte, где может быть переполнение (целочисленное значение, возможно, выходит за пределы того, что может представлять byte), и вы получаете несвязанный/неправильный номер. Но все же, на мой взгляд, это было бы более согласуется с тем, что не было неявных преобразований из decimal в плавающую точку, если они также не имели эти другие преобразования, которые вызывают потерю точности.

Ответ 3

  • В отношении интегральных типов подразумевается "точность" и "величина". не число n полностью отличается от числа n + 1 в отличие от реальные числа, где 3.333333 и 3.333329 можно считать близкими достаточно для вычисления (то есть в зависимости от того, какой точный программист хочет)

"Точность" определяет количество цифр, которое может переносить число. Один байт может содержать только две десятичные цифры, если вы (для простоты) кодируете их в BCD. Допустим, у вас есть 2 байта. Вы можете использовать их для кодирования чисел 0-9999 в целочисленном формате или вы можете определить формат, в котором последняя цифра означает десятичный показатель.

Вы можете кодировать тогда 0-999 * (10 ^ 0 - 10 ^ 9)

Вместо кодирования чисел от 0 до9999 вы можете кодировать номера до 999 000 000 000. Но если вы отбрасываете 9999 из целого формата в новый формат, вы получаете только 9990. Вы получили диапазон возможных чисел (ваша величина), но вы потеряли точность.

С двойниками и float вы имеете следующие значения, которые могут быть точно представлены: (int = 32 бит, long = 64 бит, оба подписаны:)

int → float -2 ^ 24 - 2 ^ 24

int → double все значения

long → float -2 ^ 24 - 2 ^ 24

long → double -2 ^ 53 - 2 ^ 53

Не позволяет неявное преобразование из long, чтобы плавать приглашение к тонким ошибкам, поскольку оно может привести к долгому "бесшумному" потере ценности (как программисту С#, к которому я привык к компилятору), выполняя отличную работу по защите меня от такие проблемы)

Да, он вводит тихие ошибки. Если вы ожидаете, что компилятор даст вам какую-либо помощь в решении этих проблем, забудьте об этом. Ты сам по себе. Я не знаю какого-либо языка, который предупреждает об утрате точности.

Одна из таких ошибок: Ракета Ariane...

Ответ 4

max long значение может быть помещено в float как

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

хотя long - тип 64bit Integer, а float - 32bit, но способ управления компьютером float's отличается от long's. Но для float больший диапазон достигается за счет точности.

long имеют гораздо более высокую точность, чем float, но поплавок имеет более высокий порядок величины 10 ^ 38 по сравнению с long 10 ^ 18.

Я не думаю, что они допустили ошибку, позволяющую неявное преобразование от long до float, поскольку float по-прежнему является точным до 7 цифр. Поэтому, если кто-то требует большей точности, они всегда могут использовать double или decimal`

double -15-16 цифр (64 бит)

Decimal -28-29 Значимые цифры (128 бит)

Ответ 5

При дальнейшем мышлении, кажется, все три ответа (которые более/менее указывают на одно и то же) способны правильно объяснить "почему" его часть.

  • float и длинные оба являются численными типами
  • диапазон 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;

Вопрос о долговременном потере его стоимости прибыл только тогда, когда можно было спокойно вернуть обратно конвертированный.

Спасибо всем за то, что помогли мне улучшить свое понимание.