Плохой материал может произойти при делении 1/a очень маленького плавания?

Если я хочу проверить, что положительное плавание A действительно ли меньше, чем инверсия является квадратом другого положительного плавания B (в C99), что-то могло пойти не так, как надо, если B является очень маленьким?

Я мог предположить проверять его как

if(A<1/(B*B))

Но если бы B является достаточно маленьким, это возможно привело бы к бесконечности? Если бы это должно было произойти, то код все еще работал бы правильно во всех ситуациях?

В том же духе я мог бы сделать

if(1/A>B*B)

... который мог бы быть немного лучше, потому что B*B мог бы быть нулем, если B является маленьким (действительно ли это верно?)

Наконец, решение, что я не могу предположить быть неправым,

if(sqrt(1/A)>B)

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

Так в основном мои вопросы:

  • 1/X может когда-либо быть бесконечностью, если X является больше, чем нуль (но маленьким)?
  • X*X может когда-либо быть нулем, если X больше, чем нуль?
  • Будут сравнения с бесконечностью прокладывать себе путь, я ожидал бы их к?

Править: для тех из Вас, кто задается вопросом, я закончил тем, что делал

if(B*A*B<1) 

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

7
задан Aziz Shaikh 1 October 2012 в 08:22
поделиться

4 ответа

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

Предложение использовать a * b * b <1. - хорошее предложение; если b настолько мал, что a * b * b опустится до нуля, то a обязательно меньше, чем 1 ./ (b * b) . И наоборот, если b настолько велико, что a * b * b переполняется до бесконечности, то условие (правильно) не будет выполнено. ( Potatoswatter правильно указывает в комментарии к другому сообщению, что это не работает должным образом, если вы напишете его b * b * a , потому что b * b может переполняться до бесконечности, даже если условие должно быть истинным, если a оказывается денормальным. Однако в C умножение ассоциируется слева направо, так что это не проблема, если вы пишете это a * b * b , и ваша платформа придерживается разумной числовой модели.)

Потому что вы знаете a priori , что a и ] b являются положительными числами, для a * b * b невозможно сгенерировать NaN, поэтому вам не нужно беспокоиться об этом условии. Единственное возможное неправильное поведение - это переполнение и недостаточное количество ресурсов, и мы уже учли их. Если вам нужно было поддержать случай, когда a или b может быть нулем или бесконечностью, тогда вам нужно быть несколько более осторожным.

Чтобы ответить на ваши прямые вопросы: (ответы предполагают арифметику IEEE-754)

Может ли 1 / X когда-либо быть бесконечностью, если X больше нуля (но мало)?

Да! Если x - небольшое положительное денормальное значение, тогда 1 / x может переполниться и произвести бесконечность. Например, при двойной точности в режиме округления по умолчанию 1 / 0x1.0p-1024 будет переполняться.

Может ли X * X когда-либо быть нулевым, если X больше нуля?

Да! При двойной точности в режиме округления по умолчанию все значения x меньше 0x1.0p-538 (то есть 2 ** - 578 в шестнадцатеричном формате C99) или около того имеют это свойство .

Будут ли сравнения с бесконечностью работать так, как я ожидал?

Да! Это одна из лучших особенностей IEEE-754.

7
ответ дан 6 December 2019 в 12:46
поделиться

Хорошо, репост в качестве ответа.

Попробуйте использовать арифметически эквивалентное сравнение, например if (A * B * B <1.) . Однако у вас могут возникнуть проблемы с действительно большими числами.

Внимательно изучите IEEE 754 для своих угловых случаев.

5
ответ дан 6 December 2019 в 12:46
поделиться

Вы хотите избежать деления, поэтому хитрость заключается в изменении уравнения. Вы можете умножить обе стороны первого уравнения на (b*b), чтобы получить:

b*b*a < 1.0

Это не будет иметь никаких делений, так что все будет в порядке.

3
ответ дан 6 December 2019 в 12:46
поделиться

Деление как таковое не так уж плохо. Однако стандартные типы IEEE 754 FP допускают больший диапазон отрицательных экспонент, чем положительных, из-за денормализации чисел. Например, float варьируется от 1.4×10-45 до 3.4×10-38, поэтому вы не можете взять обратную величину 2×10-44.

Поэтому, как предлагает Джереми, начните с умножения A на B, где одно из чисел имеет положительную экспоненту, а другое - отрицательную, чтобы избежать переполнения.

Вот почему A*B*B<1 является правильным ответом.

1
ответ дан 6 December 2019 в 12:46
поделиться
Другие вопросы по тегам:

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