将两个整数相除而不转换为双精度
我有两个整数变量,partial
和 total
。这是一个进度,因此 partial
从零开始,逐一上升到 total
的值。
如果我想获得指示进度的分数值(从 0.0 到 1.0),我可以执行以下操作:
double fraction = double(partial)/double(total);
但如果总计太大,转换为 double 可能会丢失信息。
实际上,丢失的信息量是可以容忍的,但我想知道是否有一种算法或标准函数来获取丢失较少信息的两个值之间的分数。
I have two integer variables, partial
and total
. It is a progress, so partial
starts at zero and goes up one-by-one to the value of total
.
If I want to get a fraction value indicating the progress(from 0.0 to 1.0) I may do the following:
double fraction = double(partial)/double(total);
But if total is too big, the conversion to double may lose information.
Actually, the amount of lost information is tolerable, but I was wondering if there is a algorithm or a std function to get the fraction between two values losing less information.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
显而易见的答案是将
partial
乘以某个缩放因子;100
是一个常见的选择,因为除法给出的百分比为整数值(向下舍入)。问题是如果这些值是
太大以至于无法用
double
精确表示,有乘以缩放因子也很有可能
溢出。 (就此而言,如果它们那么大,则初始值
在大多数机器上都会溢出
int
。)The obvious answer is to multiply
partial
by some scaling factor;100
is a frequent choice, since the division then gives the percent asan integral value (rounded down). The problem is that if the values are
so large that they can't be represented precisely in a
double
, there'salso a good chance that the multiplication by the scaling factor will
overflow. (For that matter, if they're that big, the initial values
will overflow an
int
on most machines.)是的,有一种算法丢失的信息更少。假设您想要找到最接近分数数学值的 double 值,则需要一个能够保存total << 的整数类型。 53. .您可以创建自己的库或使用 GMP 等库。然后
partial
以使(total << 52) <= numerator < (total << 53)
,其中分子 = (partial << m)
q
为整数商分子 / 总计
和r = 分子 % 总计
尾数 = q
如果2*r
总计
,如果2*r >
,如果= q+1
总计2*r == 总计
,则尾数= q+1
如果要向上舍入一半,则= q
如果你想向下舍入一半,则取两者的偶数如果你想要四舍五入到偶数result = scalbn(mantissa, -m)
大多数时候你得到的值与
(双)部分/ (double)total
,一个最低有效位的差异可能并不太罕见,两个或三个 LSB 差异也不会让我感到惊讶,但很罕见,更大的差异不太可能(也就是说,有人可能会给出很快就会有一个例子)。现在,值得付出努力吗?通常不会。
Yes, there is an algorithm losing less information. Assuming you want to find the
double
value closest to the mathematical value of the fraction, you need an integer type capable of holdingtotal << 53
. You can create your own or use a library like GMP for that. Thenpartial
so that(total << 52) <= numerator < (total << 53)
, wherenumerator = (partial << m)
q
be the integer quotientnumerator / total
andr = numerator % total
mantissa = q
if2*r < total
,= q+1
if2*r > total
and if2*r == total
,mantissa = q+1
if you want to round half up,= q
if you want to round half down, the even of the two if you want round-half-to-evenresult = scalbn(mantissa, -m)
Most of the time you get the same value as for
(double)partial / (double)total
, differences of one least significant bit are probably not too rare, two or three LSB difference wouldn't surprise me either, but are rare, a bigger difference is unlikely (that said, somebody will probably give an example soon).Now, is it worth the effort? Usually not.
如果你想要分数的精确表示,你需要某种包含分子和分母作为整数的结构,并且,为了唯一的表示,你只需分解出最大公约数(零的特殊情况) )。如果您只是担心经过重复运算后浮点表示可能不够准确,您只需找到一些有关数值分析的课程,因为这个问题严格来说并不是一个编程问题。有比其他方法更好的方法来计算某些结果,但我无法真正深入研究它们(我从未完成过课程作业,只是阅读了它)。
If you want a precise representation of the fraction, you'd have some sort of structure containing the numerator and the denominator as integers, and, for unique representation, you'd just factor out the greatest common divisor (with a special case for zero). If you are just worried that after repeated operations the floating point representation might not be accurate enough, you need to just find some courses on numerical analysisas that issue isn't strictly a programming issue. There are better ways than others to calculate certain results, but I can't really go into them (I've never done the coursework, just read about it).