Я хочу написать совместимое с IEEE-754 деление на C ++, особенно в отношении деления на ноль: positive/0->Inf
, negative/0->-Inf
, everything else/0->NaN
,
В то время как простое разделение C ++ на моей машине В результате такого поведения стандарт C ++ не предписывает эту семантику. Вместо этого он не определен, поэтому я не могу на него полагаться.
Так какой же самый быстрый способ реализовать это в C ++? Конечно, я могу сделать явный тест, как это:
double fdiv64(double numerator, double denominator)
{
using limits=std::numeric_limits<double>;
if (denominator==0.0) {
if (numerator>0.0) {
return limits::infinity();
} else if (numerator<0.0) {
return -limits::infinity();
} else {
return limits::quiet_NaN();
}
} else {
return numerator/denominator;
}
}
Но это приводит к появлению дополнительных веток и совершенно излишне на моей машине, так как я все равно получаю правильное поведение на нем. Кажется, не существует встроенного компилятора, который бы соответствовал IEEE-754-совместимому разделению. Я мог бы использовать встроенную сборку, но это тоже непереносимо.
Так какой же самый быстрый способ сделать это разделение?
Боюсь, вы не сможете сделать это мобильно, если вы не создадите свою собственную реализацию IEEE754 с плавающей запятой в программном обеспечении для платформ, которые не используют его изначально, и даже в этом случае будут небольшие различия, поскольку ваш тип не будет встроенный тип (например, &&
а также ||
не будет короткого замыкания, если вы их перегружаете); хотя пользовательские литералы может помочь
Например, поддержка infinity
является необязательным и присутствует на платформе только в том случае, если std::numeric_limits<T>::has_infinity == true
для вашего типа T
,
Так что попытки оптимизировать ваш якобы переносимый код даже не на столе.
Рекомендации:
http://en.cppreference.com/w/cpp/types/numeric_limits/infinity
http://en.cppreference.com/w/cpp/language/user_literal
Вы можете уже иметь это, не делая ничего особенного. На нескольких архитектурах вы можете указать, что ЦП должен делать в «особых» ситуациях (деление на ноль и т. Д.). Посмотри на fesetenv
, Компиляторы обычно имеют переключатели о том, как они должны обрабатывать математические вычисления с плавающей точкой. Например, посмотрите на cl.exe в Visual Studio вариант об этом.
Если вы остаетесь на архитектуре x86 (и используете SSE или x87 с внутренней точностью, установленной на float / double, подробности смотрите по ссылкам ниже), я думаю, что вы можете положиться на поведение IEEE754 из коробки (поэтому ваша программа будет работать на любом x86 машина, а не только твоя).
Если у вас есть процессор, который не может следовать IEEE754, то вам, возможно, придется использовать полную программную реализацию с плавающей запятой. Или, может быть, вы можете использовать HW, и вам нужно только обрабатывать исключительные случаи.
Но обычно сегодня почти все (ПК, мобильные устройства) используют IEEE754:
В реализации SW вы должны извлечь знак, экспоненту, мантиссу из числа с плавающей запятой и выполнить математику самостоятельно.
Примечание. Вы можете получить результат inf, даже если делитель не ноль, а небольшое (субнормальное) число. Это потому, что макс. число для числа с плавающей точкой находится в диапазоне ~ 10 ^ 38, но минимальное, но положительное число находится в диапазоне ~ 10 ^ -45.