Я знаю, я знаю, люди, вероятно, скажут «просто переключитесь на плавающую точку», но в настоящее время это не вариант из-за характера проекта, над которым я работаю. Я помогаю писать язык программирования на C ++, и в настоящее время мне сложно получить очень точный алгоритм умножения, при котором у меня есть виртуальная машина и, в основном, операции для mod / smod, div / sdiv (т.е. числа со знаком здесь не важны ), mul, уменьшенное вдвое число для полностью дробных чисел и номер сдвига, который я умножаю и делю, чтобы создать сдвиг. Для простоты предположим, что я работаю с 32-байтовым пространством. Мои алгоритмы отлично работают практически для всего, что связано с целыми числами, просто когда моя дробная часть превышает 16 байтов, у меня возникают проблемы с точностью, и если бы я округлил его, число было бы довольно точным, но я хочу, чтобы оно было точнее, насколько это возможно, даже готов пожертвовать чуть-чуть производительностью ради этого, пока он остается фиксированной точкой и не переходит в землю с плавающей запятой. Алгоритмы, которые меня интересуют, я обозначу в виде псевдокода. Хотел бы получить какое-либо представление о том, как я могу это сделать лучше, или какие-либо рассуждения о том, почему по законам вычислительной науки то, что я прошу, является бесплодным усилием.
Для полностью дробных чисел (все байты дробные):
A = num1 / halfShift //truncates the number down to 16 so that when multiplied, we get a full 32 byte num
B = num2 / halfShift
finalNum = A * B
Для остальных моих чисел, размер которых превышает 16 байт, я использую этот алгоритм:
this algorithm can essentially be broken down into the int.frac form
essentially A.B * C.D taking the mathematic form of
D*B/shift + C*A*shift + D*A + C*B
if the fractional numbers are larger than the integer, I halve them, then multiply them together in my D*B/shift
just like in the fully fractional example above
Есть ли какой-то «волшебный» метод округления, о котором мне следует знать? Пожалуйста, дай мне знать.
A = num1 / halfShift //truncates the number down to 16
- как только вы уменьшите точность (разрешение, на самом деле) ввода (здесь до 16, а единица измерения (байты / цифры / биты / слова ...) имеет еще меньшее значение), нет количества точных арифметических действий можно восстановить / увеличить. Вместо этого выберите, сколько охранных мест вам потребуется (скажем, 2), и вычислите с выбранной точностью (32 + 2 = 34 в данном случае). В случае умножения это позволяет отбросить почти половину неполных произведений. Округлить до окончательной точности. - person greybeard   schedule 08.07.2016@
(вы получите предложения) .) - person greybeard   schedule 09.07.2016