Могу ли я сравнить две дроби, если оба имеют знаменатель со степенью 2 - PullRequest
4 голосов
/ 06 июня 2011

Я знаю, что "невозможно" сравнивать два действительных, но верно ли это для реального, у которого сила знаменателя равна 2

Всегда ли равенство этого короля возвращает true

if( 3/4. == 6/8. ) {}

Ответы [ 4 ]

4 голосов
/ 06 июня 2011

Этот тип выражения всегда должен оцениваться как true с несколькими оговорками:

  • Числители не превышают 2 ^ 52;в противном случае они потеряют точность.
  • Знаменатели не превышают диапазон, обеспечиваемый двойной точностью.
  • Вы должны работать на платформе, которая использует число с плавающей точкой radix-2это в основном все современные машины).
3 голосов
/ 06 июня 2011

Я не могу процитировать ничего, что говорит, что гарантировано , но логически это должно работать, потому что все числа с плавающей запятой IEE754 представлены как M * 2 ^ E, где M и E оба являются целыми числами (и могут быть отрицательным).

Следовательно, 3 / 4.0 и 6 / 8.0 оба точно равны 3 * 2 ^ -2 и полностью представимы в формате IEE754.

Кроме того, дано:

% cat test.cc
double three_quarters = 3 / 4.0;
double six_eighths = 6 / 8.0;

Получаем:

% c++ -S test.cc
% cat test.s
.globl _three_quarters
        .data
        .align 3
_three_quarters:
        .long   0
        .long   1072168960
.globl _six_eighths
        .align 3
_six_eighths:
        .long   0
        .long   1072168960

Что показывает, что оба выражения были уменьшены (компилятором) до одного и того же постоянного значения.

1 голос
/ 06 июня 2011

Нет требования, чтобы реализации C ++ использовали плавающую точку IEEE 754 (или аналогичную).Но если у вас есть, это должно работать нормально.

0 голосов
/ 06 июня 2011

В целом, работает ли сравнение с плавающей запятой, зависит не от значений, а от того, как они были получены.

, например

 double v = 4/3.0; // inexact
 double old_v = v;
 some_func_that_might_change_its_argument(&v);
 if (v == old_v) { ... }

, вероятно, будет работать хорошо, несмотря на неточное значение, тогда как:

 double v = 0;
 for( int i = 0; i < 5; ++i ) v += 0.1;
 if (v == 0.5) { ... }

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

...