2016-03-05 3 views
-1

У меня есть функция, как:Потеря точности?

double calc(double x); 

ли я потерять точность, с какой-либо из этих выражений:

double y1 = calc(1.0/3); 
double y2 = calc(1.0/3.0); 

Являются ли эти более точные:

double y3 = calc(static_cast<double>(1)/3) 
double y4 = calc(static_cast<double>(1)/static_cast<double>(3)) 

РЕДАКТИРОВАНИЕ

Извините, у меня было t он ошибается здесь.

Но я имел в виду, что это 1.0 интерпретируется как float или double, и это всегда так, или это зависит от некоторых флагов компилятора? Если это float, то 1.0/3 также будет float и только после этого будет преобразован в double. Если это так, это приведет к потере точности, не так ли?

EDIT 2

Я испытал это с g++ и, как выясняется, если программа составлена ​​с -fsingle-precision-constant флагом, вы сделать теряют точность.

#include <iostream> 
#include <limits> 
#include <typeinfo> 

long double calc(long double val) 
{ 
    return val; 
} 
int main() { 
    std::cout.precision(std::numeric_limits< long double >::max_digits10); 

    std::cout << calc(1.0/3.0) << std::endl; 
    std::cout << calc(static_cast<float>(1)/3) << std::endl; 
    std::cout << calc(static_cast<double>(1)/3) << std::endl; 
    std::cout << calc(static_cast<long double>(1)/3) << std::endl; 
    std::cout << typeid(1.0).name() << std::endl; 

    return 0; 
} 

Результаты,

0.333333343267440795898 
0.333333343267440795898 
0.33333333333333331483 
0.333333333333333333342 
f 

Итак, я решил использовать static_cast< long double >(1)/3, чтобы быть на безопасной стороне.

+0

Dunno. Что случилось, когда вы попробовали? –

+0

No ............. –

+3

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

ответ

3

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

В частности, целые значения [ниже числа биттов мантиссы] всегда представлены точно.

[Очевидно, что мы понятия не имеем, что calc делает с входом - что может быть источником любого и всех видов ошибок, но я предполагаю, вы на самом деле просят, если 3.0/8.0 всегда будет в случаях 0.375 вы предложили - конечно 3/8 приведет к нулю, так как это число с обеих сторон]

редактировать в ответ на первоначальный вопрос редактируется:

Если код говорит 1. или 1.0 или 0.3 или .3, его является double , Если вы пишете 0.5f, это float. Согласно правилам, приведенным выше 1.0/3, результат будет double(1.0)/double(3.0).

Технически возможно, чтобы компилятор поддерживал только один тип с плавающей запятой, с тремя различными способами написания: - стандарты C и C++ не требуют от double, чтобы иметь больше бит, чем float.

+0

Я отредактировал вопрос. Не могли бы вы еще раз взглянуть и пересмотреть свой ответ? – Eliad

+0

Все еще применяется. Я добавил немного разъяснений относительно того, почему. –

0

Номер. Постоянное выражение для y1: неявно преобразован в double. Постоянное выражение для y2 уже является double.

Что вы делаете в y3 и y4 является определяющим постоянное целое значение и приведения его к double, когда вы можете просто определение постоянной двойной точности с плавающей точкой, как вы уже сделали.

+0

Чуть более точно, для 'y1'' 8' (неявно) преобразуется в 'double', чтобы соответствовать' 3.0'. Результат деления этих двух двойников имеет тип double; там никакой конверсии не требуется. –