с плавающей запятой — предотвращение неявных преобразований с плавающей запятой в переполнение стека

В принципе, если я хочу что-то подобное,

double b = sin(2.2);

но случайно напишу что-то вроде этого,

double b = sin(2.2f);

нет сообщения об ошибке или даже предупреждения, даже если это явно приводит к другому, неточному и, следовательно, неверному результату. Этот тип ошибки можно предотвратить, если заставить компилятор не делать никаких неявных преобразований типа float в double. Есть ли способ достичь этого, будь то с помощью переключателя компиляции (предпочтительно в Visual Studio), некоторых интеллектуальных макросов или класса, который ведет себя как переменные типа float / double и объявляет свои собственные операторы?

Изменить: я также заинтересован в решении аналогичных проблем с использованием операторов (например, double b = 2.2f * 2.2f) или присваивания (double b = 2,2f).

6

Решение

Вы можете использовать type_assert полезность.

Пример:

#include <cmath>
#include <type_traits>

template<typename T, typename U>
const U& type_assert(const U& u) {
static_assert(std::is_same<T, U>::value, "...");
return u;
}

int main() {
double t = type_assert<double>(std::sin(2.2f));
}

Если ожидаемый тип отличается, он выдаст ошибку компилятора. Скорее всего, компилятор может оптимизировать это, если он пройдет, по крайней мере, в моем случае с -O3,

5

Другие решения

Вы можете сделать вызов sin(float) неоднозначный, определяя что-то вроде

double sin(float x) { abort(); }

Тогда звонки sin на float даст вам ошибку во время компиляции. Это работает, потому что в cmath заголовок, std::sin перегружена функция с float sin(float), double sin(double), а также long double sin(long double) варианты. Компилятор не может знать, хотел ли ты ::sin(float) или же std::sin(float), поэтому он вскидывает руки в замешательстве.

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

4

Что-то вроде того?

class MyDouble{
public:
MyDouble(float _f) {throw "only use double!";}
MyDouble(double _d) : m_data(_d) {}

operator float() const {throw "conversion to float occurred!";}
operator double() const {return m_data;}

private:
double m_data;
};

но да, вам придется начать использовать этот класс в своих вызовах математических функций, что делает его очень уродливым:

MyDouble d(3.2);
sin(d);
// or...
cos(MyDouble(2.3));

ОБНОВИТЬ — Пример реализации оператора (бинарный оператор, поскольку унарный должен быть частью класса):

MyDouble operator+(const & MyDouble _lhs, const & MyDouble _rhs){
MyDouble rez(_lhs);
rez += _rhs;
return rez;
}

Конечно, вам не нужно реализовывать это таким образом (используя ярлык operator+=) но это делает код легче поддерживать

2

Я только что понял, что вы используете Microsoft продукт, но я оставлю этот ответ, так как он может помочь кому-то еще.

Вы смотрели через переключатели компилятора? Я предполагаю, что есть подобный вариант.

О, МОЙ БОГ! Я только что искал помощь с опциями и предупреждениями Visual Studio! (ссылка на сайт)

я ТАК извиняюсь! Я не знал! Это один из наименее полезные списки опций и переключателей, которые я когда-либо видел! Еще более иронично, они начали собирать StackOverflow для получения ответов и ссылок здесь.

Но я нашел некоторые подсказки:

Предупреждение компилятора (уровни 3 и 4) C4244
преобразование ‘преобразование из’ type1 ‘в’ type2 ‘, возможная потеря данных

Используется таким образом:

// Enable this to find unintended double to float conversions.
// warning C4244: 'initializing' : conversion from 'double' to 'float', possible loss of data
#pragma warning(3 : 4244)

GCC / G ++ переключатели (

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

Со страницы руководства g ++ / gcc:

-Wdouble-promotion (C, C++, Objective-C and Objective-C++ only)
* Give a warning when a value of type "float" is implicitly promoted to "double".
... some verbage clipped ...
* It is easy to accidentally do computations with "double" because floating-point
literals are implicitly of type "double".

Добавление -Wdouble-promotion на ваш CXXFLAGS должен предоставить вам предупреждения во время компиляции.

Существует также -fsingle-precision-constant который запрещает неявное преобразование чисел с плавающей точкой в ​​двойники.

2
По вопросам рекламы [email protected]