Есть ли решение для арифметических задач с плавающей точкой в ​​C ++? - PullRequest
0 голосов
/ 28 октября 2010

Я делаю некоторую арифметику с плавающей точкой и имею проблемы с точностью.Результирующее значение отличается на двух машинах для одного и того же ввода.Я прочитал пост @ Почему я не могу умножить число с плавающей запятой? , а также прочитал другие материалы в Интернете и понял, что это связано с двоичным представлением с плавающей запятой и с машинным эпсилоном.Тем не менее, я хотел проверить, есть ли способ решить эту проблему / Некоторые обходные пути для арифметики с плавающей точкой в ​​C ++ ??Я конвертирую float в unsigned short для хранения и конвертирую обратно при необходимости.Однако, когда я преобразую его обратно в беззнаковое короткое, точность (до 6 десятичных знаков) остается правильной на одной машине, но не на другой.

//convert FLOAT to short

unsigned short sConst = 0xFFFF;

unsigned short shortValue = (unsigned short)(floatValue * sConst);

//Convert SHORT to FLOAT

float floatValue = ((float)shortValue / sConst);

Ответы [ 4 ]

2 голосов
/ 28 октября 2010

A short должно быть не менее 16 бит, и во многих реализациях это именно то, что есть.unsigned 16-битный short будет содержать значения от 0 до 65535. Это означает, что короткое не будет содержать целых пять цифр точности, и, конечно, не шесть.Если вам нужно шесть цифр, вам нужно 20 бит.

Таким образом, любая потеря точности вероятна из-за того, что вы пытаетесь упаковать шесть цифр точности во что-то менее пяти цифр.Нет никакого решения для этого, кроме использования целочисленного типа, который, вероятно, занимает столько же памяти, сколько float.

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

1 голос
/ 28 октября 2010

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

Точное определение «слишком много» полностью зависит от вашего приложения. Например, если вы вычисляете a + b на разных платформах, вы должны найти, что эти два результата находятся в пределах точности станка друг для друга. С другой стороны, если вы делаете что-то более сложное, например, инверсию матрицы, результаты, скорее всего, будут отличаться больше, чем точность машины. Точное определение того, насколько близко можно ожидать результатов, является очень тонким и сложным процессом. Если вы точно не знаете, что делаете, возможно, безопаснее (и разумнее) определить степень точности, которая вам нужна в последующих приложениях, и убедиться, что результат достаточно точный.

Чтобы получить представление о том, как надежно вычислить относительную ошибку между двумя значениями с плавающей запятой, см. Этот ответ и руководство по ним с плавающей точкой:

Функции сравнения с плавающей запятой для C #

0 голосов
/ 17 декабря 2011

Вместо 0xFFFF используйте половину, то есть 32768 для преобразования. 32768 (Ox8000) имеет двоичное представление 1000000000000000, в то время как OxFFFF имеет двоичное представление 1111111111111111. Бинарное представление Ox8000 явно подразумевает, что операции умножения и деления во время преобразования (в короткое (или) при преобразовании обратно в float) не изменят значения точности после нуля. Однако для одностороннего преобразования предпочтительным является OxFFFF, поскольку он приводит к более точному результату.

...