重要编辑:最初的问题是关于获得双打和分数的密度。当我得到双打而不是分数的答案时,我正在改变主题以关闭这个问题。原始问题的另一半是here
我想找到2个给定数字之间的双打密度,但我不能想到一个好方法。所以我正在寻找一个封闭形式的表达式doublesIn(a,b)。或者是一些在合理的时间内完成工作的代码。
对于双打,我应该使用一些带有尾数和指数的公式我不知道。我已经有一个使用 nextafter 的代码,并且它接近[-1,1]非常缓慢(低于1e6非常慢)
有什么想法吗?提前致谢! :)
PS:如果你想知道,我为自己编写了一些数学的东西,我想找到在某些算法(如Gaussian)上用一个分数(长,长或类似)替换double的有用之处。消除,牛顿寻找根等方法,为此我想采取一些措施。答案 0 :(得分:1)
在下文中,包括程序,我假设double
由IEEE 754 64位二进制浮点表示。这是最可能的情况,但不能保证C ++标准。
您可以在恒定时间内计算范围内的双精度数,因为您可以通过从结尾减去开始并调整范围是打开还是关闭来计算恒定时间范围内的无符号整数。
有限非负范围内的双精度数具有形成连续整数序列的位模式。例如,范围[1.0,2.0]包含[0x3ff0_0000_0000_0000,0x4000_0000_0000_0000]范围内每个整数的一个双精度。
有限的非正范围的双精度表现方式相同,只是无符号位模式的值随着双精度变得更负而增加。
如果您的范围包含正数和负数,请将其拆分为零,以便处理一个非负范围和另一个非正范围。
当您想要完全正确地计算时,大多数并发症都会出现。在这种情况下,您需要调整范围是打开还是关闭,并且只需计算一次零。
出于你的目的,在几亿人中被一两个人关闭可能并不重要。
这是一个演示这个想法的简单程序。它收到的错误检查很少,因此使用风险自负。
#include <iostream>
#include <cmath>
using namespace std;
uint64_t count(double start, double end);
void testit(uint64_t expected, double start, double end) {
cout << hex << "Should be " << expected << ": " << count(start, end)
<< endl;
}
double increment(double data, int count) {
int i;
for (i = 0; i < count; i++) {
data = nextafter(data, INFINITY);
}
return data;
}
double decrement(double data, int count) {
int i;
for (i = 0; i < count; i++) {
data = nextafter(data, -INFINITY);
}
return data;
}
int main() {
testit((uint64_t) 1 << 52, 1.0, 2.0);
testit(5, 3.0, increment(3.0, 5));
testit(2, decrement(0, 1), increment(0, 1));
testit((uint64_t) 1 << 52, -2.0, -1.0);
testit(1, -0.0, increment(0, 1));
testit(10, decrement(0,10), -0.0);
return 0;
}
// Return the bit pattern representing a double as
// a 64-bit unsigned integer.
uint64_t toInteger(double data) {
return *reinterpret_cast<uint64_t *>(&data);
}
// Count the doubles in a range, assuming double
// is IEEE 754 64-bit binary.
// Counts [start,end), including start but excluding end
uint64_t count(double start, double end) {
if (!(isfinite(start) && isfinite(end) && start <= end)) {
// Insert real error handling here
cerr << "error" << endl;
return 0;
}
if (start < 0) {
if (end < 0) {
return count(fabs(end), fabs(start));
} else if (end == 0) {
return count(0, fabs(start));
} else {
return count(start, 0) + count(0, end);
}
}
if (start == -0.0) {
start = 0.0;
}
return toInteger(end) - toInteger(start);
}