2012-02-08 2 views
3

У меня есть две целые переменные, partial и total. Это прогресс, поэтому partial начинается с нуля и увеличивается один за другим до значения total.Разделение двух целых чисел без литья в double

Если я хочу, чтобы получить значение дроби, показывающее ход (от 0.0 до 1.0), я могу сделать следующее:

double fraction = double(partial)/double(total); 

Но если общая сумма слишком велика, преобразование в два раза может привести к потере информации.

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

+3

'double' имеет 53 бит мантиссы - вы говорите, что' total' может быть> 53 бит? –

+6

Каковы типы данных 'partial' и' total'? IIRC «double» может содержать любое значение, 32-битовое целое может без потери точности. –

+1

Ну, 'total' должно иметь значение'> 2^53', которое составляет примерно 16-значное число в десятичном формате. Я действительно задаюсь вопросом, есть ли у вас такие большие числа. В этом случае я надеюсь, что ваши целые числа равны 64 битам, так как в противном случае их не хватит в первую очередь. –

ответ

7

Очевидным ответом является умножение partial на некоторый масштабный коэффициент; 100 является частым выбором, так как деление затем дает процент, равный , интегральное значение (округленное вниз). Проблема в том, что если значения настолько велики, что они не могут быть представлены точно в double, то есть также хорошая вероятность того, что умножение на коэффициент масштабирования будет переполнение. (В этом случае, если они такие большие, начальные значения переполнят int на большинстве машин.)

0

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

1

Да, есть алгоритм, теряющий меньше информации. Предполагая, что вы хотите найти значение double, самое близкое к математическому значению фракции, вам нужен целочисленный тип, способный удерживать total << 53. Вы можете создать свой собственный или использовать для этого библиотеку, такую ​​как GMP. Тогда

  • шкала partial так что (total << 52) <= numerator < (total << 53), где numerator = (partial << m)
  • пусть q быть целое частное numerator/total и r = numerator % total
  • пусть mantissa = q если 2*r < total, = q+1 если 2*r > total и если 2*r == total, mantissa = q+1 если вы хотите, чтобы закруглить половину вверх , = q, если вы хотите округлить половину, даже если вы хотите, чтобы круглый полу-четный
  • result = scalbn(mantissa, -m)

Большую часть времени вы получите такое же значение, как и для (double)partial/(double)total, различия в младшем бит, вероятно, не слишком редко, два или три LSB разница не удивило бы меня тоже, но являются достаточно редкими, большая разница маловероятна (это говорит, что кто-то, вероятно, скоро представит пример).

Теперь это стоит усилий? Обычно нет.

Смежные вопросы