我正在努力准确地说明本初子午线的交叉点 我遇到了关于IEEE浮点运算的以下问题 (舍入到最近):
让 n 为整数, d 为小正数。确实
y = n * 360 - d < n * 360
保证楼层( y / 360)< 名词的?这里所有操作(* - < / floor)都是 被理解为浮动操作(使用例如双精度IEEE)。
如果这个问题中的360被其他一些积极的东西取代怎么办? 浮点数。 (每当浮动时都会出现同样的问题 点数被分配给均匀分布的箱。)
答案 0 :(得分:0)
n * 360 - d < n * 360
- &gt; 0 - d < 0
- &gt; d > 0
为真,因为“ d (是) small 正数”。
到目前为止,n
的价值无关紧要。
y = n * 360 - d
- &gt; y/360 = n - d/360
- &gt;
0.0 <= q < 1.0
,
floor(y/360) + q = n - d/360
- &gt; floor(y/360) - n = -q - d/360
对于q
和d
的所有值,-q - d/360 < 0
- &gt;
floor(y/360) - n < 0
- &gt; floor(y/360) < n
。 Q.E.D.
如果360被x
替换为任何大于0的整数,答案仍然是相同的。如果将x
替换为任何数字&gt; = 1.0,我认为也是如此。必须考虑0 < x < 1
。
d
的最小到目前为止无关紧要 - 只是它是一个正数(d > 0
)。
答案 1 :(得分:0)
经过一些实验,我想我可以提供部分答案。让我来 改写问题:写一个函数
int bin(double x, double m)
计算
int(floor(x/m))
准确。假设 m 为正,结果在范围内 中间体
第一次尝试是
int bin0(double x, double m) {
return int(std::floor(x / m));
}
但是对于 m = 360.0和 x = -denorm_min(0是 返回而不是-1)。
由于此故障只是 x 接近于零,因此第二次尝试是
int bin1(double x, double m) {
int n = int(std::floor(x / m));
return n == 0 && x < 0 ? -1 : n;
}
我相信这会返回 n 提供的确切答案 n * m 完全可以表示为双。对于 m = 360.0,这包括所有 n 可表示为32位整数。我对吗?一个证明就是 太好了!
如果这个条件不成立,例如 m = 0.1,那么我能做到最好 想出来就是
int bin2(double x, double m) {
double z = std::fmod(x, m);
return int(std::floor((x - z)/m + 0.5)) + (z < 0 ? -1 : 0);
}
这总是会返回正确的结果吗?是否有一些&#34;清洁&#34; 溶液
ADDENDUM:在我的应用程序中,我只需要获得奇偶校验 箱号(偶数或奇数)。 (我的应用是测量a的面积 测地线多边形,我需要跟踪边缘是否环绕 极点偶数或奇数次。)所以chux的建议使用 remquo是一个很好的。不幸的是(1)std :: remquo需要C ++ 11和 (2)更严重的是,glquo的glibc实现是错误的;看到 这bug report。所以我最终基本上做了
int binparity(real x, real m) {
// return the parity of int(floor(x/m))
x = std::fmod(x, 2 * m);
return (x >= 0 && x < m) || x < -m ? 0 : 1
}