Распределять буквального плавающей точки float без суффикса

Имея в виду, что в C/C ++ буквальные плавающей точки без суффикса назначены по умолчанию типа double, тогда распределив буквального этого типа float, осуществляется подразумеваемое превращение double в float.

float n = 3.14;

if(n == 3.14f)
   puts("Igual");

Это не печатает сообщение взамен, если мы добавляем суффикс f к 3.14 в заявлении n, чтобы предотвращать превращение, если он печатается. Вопрос, случается потерянная от точности, когда превращение осуществляется?

11
задан 29.12.2016, 03:00
3 ответа

Вопрос

он случается потерянная от точности, когда превращение осуществляется?

Если, случается потеря точности.

Сужение (Narrowing).

Типы данных в плавающей запятой:

  • float: Простая точность. Обычно это тип 32 бит шириной, которые продолжает IEEE-754 32 бит.
  • double - Двойная точность. Обычно это тип 64 бит шириной, которые продолжает IEEE-754 64 бит.
  • long double - Распространенная точность. Обычно это тип 80 бит в архитектуре 32 и 64 бит. Не обязательно остается IEEE-754.

Каждый раз, когда ты переходишь с одним из типа большей точности меньше случается сужение; каждый раз, когда случается сужение могут теряться данные: когда происходит это?

Превращение типов.

Согласно стандарту C в секции §6.3.1.5 Реальные типы в плавающей запятой (перевод и выделенный мои):

6.3.1.5 Реальные типы в плавающей запятой

  1. Когда один float он продвинут в double или long double, или когда один double он продвинут в long double, Ваша стоимость не меняется.
  2. Когда один double он понижен в звании в float, один long double он понижен в звании в double или float, или стоимость, представленная в большей точности и ранге, что потребованная Вашим семантическим типом (видеть 6.3.1.8) обращено ясно в этот семантический тип, если стоимость, которая превращается, может представляться exáctamente в новом типе, не изменится. Если стоимость, которая превращается, находится в ранге стоимости, которая может быть представленной, но не может быть представленной точностью, результат будет числом, самым близким к стоимости так округляя вверх или вниз, округление зависимое от осуществления. Если стоимость, которая превращается, - вне ранга стоимости, который может быть представленным, поведение неопределенное.

В твоем случае, распределять стоимость 3.14 в один float соответствуй сужению, но как стоимость 3.14 он перепредставительный из-за float с точностью стоимость не изменится.

Что не удается?

Если стоимость не изменилась: Почему не удается твой код?:

float n = 3.14;

if(n == 3.14f)
   puts("Igual"); // no se imprime!

Потому что я лгал, стоимость 3.14 Он не является перепредставительным из-за float с точностью. Существуют числа в плавающей запятой, которые не exáctamente перепредставительные в бинарном, это проистекает из свойств каждый base1.

Стоимость 3,14 в бинарном не exáctamente перепредставительно и точно удвойте Вашу стоимость его приблизительно 3,14000000000000012434497875802, но хранили это в одном float ты потерял что-то из точности: сколько exáctamente? он будет зависеть от твоей системы...

Так что ты будешь сравнивать число, похожее на урезывание стоимости double 3,14000000000000012434497875802 против похожего числа в 3.14f что во многих случаях не будет тем же числом. Например буквального 3,14 в float приблизительно 3,1400001049041748046875 тогда твое сравнение было бы, более или менее:

if(3.1400000000000001243449 == 3.1400001049041748046875) // El double ha sido truncado

Что очевидно не выполняет равенства.

Это ужасно! что я могу делать?

Как прокомментируй eferion, ты должен избегать сравнивать числа в плавающей запятой посредством равенства, ввиду ошибок округления ты они должен сравнивать из-за почти равенство, такая функция ты могла бы помогать:

#include <stdbool.h>
#include <stdint.h> 

bool casi_iguales(float izquierda, float derecha)
{
     return fabs(izquierda – derecha) <= FLT_EPSILON;
}

bool casi_iguales(double izquierda, double derecha)
{
     return fabs(izquierda – derecha) <= DBL_EPSILON;
}

Стоимость FLT_EPSILON и DBL_EPSILON это различие между 1 и следующей перепредставительной стоимостью из-за float и double соответственно; в других словах, это приблизительно самая меньшая перепредставительная стоимость из-за каждого из типов, так что если различие между izquierda и derecha он меньший или равен этой стоимости состоит в том, что обе стоимость почти равна.


1Por пример, 1/3 в основании 10 - периодическое чистое число стоимости 0,3333333... в то время как в основании 12 - exáctamente 0.4. В десятичном стоимость 1/10 - exáctamente 0,1, но бинарным периодического смешанного числа стоимости 0,00011001100110011...

8
ответ дан 24.11.2019, 12:57
  • 1
    Смоги помогать дополнять в c и # 243; mo они представляются они n и # 250; морские окуни в бинарном: и #191; Из-за qu и # 233; мои программы не могут делать c и # 225; lculos aritm и # 233; костариканские правильно? – Mariano 25.10.2016, 11:25
  • 2
    @PaperBirdMaster Тогда важно добавлять суффикс, приспособленный к каждому буквальному, потому что я вижу, что это не вещь, которая делается очень часто. – cheroky 25.10.2016, 16:24
  • 3
    @cheroky действительно. Подходящий суффикс в моем opini и # 243; n жизненный, не s и # 243; это с n и # 250; морские окуни в плавающей запятой (.0, .0f), если не tambi и # 233; n с n и # 250; цельные морские окуни (0, 0u, 0l, 0ul, 0ll, 0ull) и цепи ("hola", L"hola", u8"hola"...). К сожалению есть типы, которые испытывают недостаток в суффиксе (short, long double, char) и мы должны использовать их со знанием:) – PaperBirdMaster 25.10.2016, 16:28

Числа в плавающей запятой никогда никогда не должны сравниваться используя оператор сравнения.

Мотив состоит в том, что вышеупомянутые числа обладают определенной точностью, будучи практически случайной оставшейся частью цифр.

Правильная форма состоит в том, чтобы реализовывать сравнение принимая некий край ошибки:

float v1,v2;
//...
if (fabs(v1-v2)<1e-4)
  // Los números son iguales
else
  // Los números son distintos

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

Приветствие

3
ответ дан 24.11.2019, 12:57

Здесь очень иллюстративный пример того, за чем оно последует. И на самом деле, что имеет смысл объяснять это.

У тебя есть две площади памяти, не инициализируя так:

Площадь В:

+--------------------------------------+
| qwerytuiopasdfhgjklzxcvbnm1234567890 |
+--------------------------------------+

Площадь B:

+--------------------------------------+
| qwerytuiopasdfhgjklzxcvbnm1234567890 |
+--------------------------------------+

Потом ты помещаешь один float в A:

+----------------+
| 3.14           | // Nota como float es más pequeño.
+----------------+

И один double в B:

+--------------------------------------+
| 3.14                                 |
+--------------------------------------+

Тогда сравнив A с B, ты получаешь сравнение:

+--------------------------------------+
| 3.14                                 |
+--------------------------------------+

С

+--------------------------------------+
| 3.14           gjklzxcvbnm1234567890 |
+--------------------------------------+

Будучи этими различные. Я надеюсь, что он казался тебе дидактическим.

2
ответ дан 24.11.2019, 12:57