Проблемы вычисления Mysql: 1+1=1.999999999

Вопреки популярному мнению возможно иметь ссылку, которая является ПУСТОЙ.

int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

Предоставленный, это намного тяжелее относится к ссылке - но если Вы будете управлять им, Вы порвете волосы, пытаясь найти его. Ссылки не по сути безопасны в C++!

Технически это недопустимая ссылка , не нулевая ссылка. C++ не поддерживает нулевые ссылки как понятие, поскольку Вы могли бы найти на других языках. Существуют другие виды недопустимых ссылок также. Любой недопустимая ссылка повышает призрак [1 119] неопределенное поведение , как использование недопустимого указателя было бы.

фактическая ошибка находится в разыменовании Нулевого указателя до присвоения на ссылку. Но я не знаю ни о каких компиляторах, которые генерируют любые ошибки на том условии - ошибка распространяет к точке далее вперед в коде. Это - то, что делает эту проблему таким образом коварной. Большую часть времени при разыменовании Нулевого указателя Вы отказываете прямо в том пятне, и не требуется большой отладки для понимания его.

Мой пример выше короток и изобретен. Вот более реальный пример.

class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(i1,i2,i3,i4,i5);  // crash occurs here due to memory access violation - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

я хочу повторить, что единственный способ получить нулевую ссылку через уродливый код, и как только у Вас есть он, Вы получаете неопределенное поведение. никогда не имеет смысл проверять на нулевую ссылку; например, можно попробовать if(&bar==NULL)..., но компилятор мог бы оптимизировать оператор из существования! Действительная ссылка никогда не может быть ПУСТОЙ так от представления компилятора, сравнение всегда является ложью, и это свободно устранить if пункт как мертвый код - это - сущность неопределенного поведения.

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

template
T& deref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(deref(p));

Для более старого взгляда на эту проблему от кого-то с лучшими навыками письма, см. Нулевые ссылки от Jim Hyslop и Herb Sutter.

Для другого примера опасностей разыменовать нулевого указателя см. Представлять неопределенное поведение при попытке портировать код на другую платформу Raymond Chen.

5
задан Ant 29 July 2009 в 20:02
поделиться

6 ответов

Эта статья довольно хорошо объясняет проблему.

Короче говоря, очень большие или очень маленькие числа с плавающей запятой могут привести к потере точности во время вычислений.

3
ответ дан 18 December 2019 в 05:55
поделиться

Добавление 1 и 1 как числа с плавающей запятой или удвоения не должно приводить ни к чему, кроме 2.

Мне трудно поверить, что 0,5 + 1,5 дает что-либо, кроме 2.

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

Мне неприятно говорить, что я не верю вашим примерам, но я не верю. : -)

Однако я верю, что у вас могут возникнуть проблемы с числом, например 1.1.

Почему? Поскольку 1/10 оказывается повторяющимся десятичным числом в двоичном формате.

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


Однако, если ваши примеры действительно работают таким образом, я понятия не имею, что происходит, и хотел бы знать.

8
ответ дан 18 December 2019 в 05:55
поделиться

Не уверен, ищете ли вы объяснение или решение, но поскольку вы уже получили указатели на хорошие объяснения ....

Если вам нужно, чтобы ваши числа вели себя как целые числа, используйте целые числа . Если вам нужна конечная степень точности (например, два десятичных знака для полей, представляющих деньги), все равно сохраните ее как целое число, но умножьте его на любой коэффициент 10, который вам нужен, чтобы избавиться от десятичной дроби, когда вы помещаете его в базу данных, и делите на то же самое, когда вы вытаскиваете его обратно.

Итак, если вы представляете виджет стоимостью 3,99 доллара вы указываете 399 в поле WIDGET.cost.

Не знаю, применимо ли это к вашей ситуации или нет. Но общее практическое правило состоит в том, что числа с плавающей запятой ВСЕГДА являются всего лишь приближением. :-) Если точность имеет значение, найдите способ использовать целые числа.

2
ответ дан 18 December 2019 в 05:55
поделиться

Не ожидайте целых чисел при работе с типами с плавающей запятой.

2
ответ дан 18 December 2019 в 05:55
поделиться

числа с плавающей запятой ВСЕГДА являются приблизительными. :-) Если точность имеет значение, найдите способ использовать целые числа.

По моему опыту,

4
ответ дан 18 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: