このプログラムを含めて、私はdouble
がIEEE 754 64ビット2進浮動小数点で表されると仮定しています。これが最も可能性の高いケースですが、C++標準では保証されていません。
終点から始点を引いて、範囲が開いているか閉じているかを調整することで、一定時間内に範囲内の符号なし整数を数えることができるため、一定時間内に2倍を数えることができます。
有限の負でない範囲の倍数は、整数の連続したシーケンスを形成するビットパターンを持ちます。たとえば、範囲[1.0,2.0]には、[0x3ff0_0000_0000_0000、0x4000_0000_0000_0000]の範囲の各整数に対して1つのdoubleが含まれます。
double型の有限の正の範囲は、double型の負の値が増えるにつれて、符号なしビットパターンの値が大きくなる点を除き、同じように動作します。
範囲に正の数と負の数の両方が含まれる場合は、ゼロで分割して、1つの非負の範囲と別の非正の範囲を扱うようにします。
多くの複雑さは、カウントを正確に取得したいときに発生します。その場合、範囲が開いているか閉じているかを調整し、正確に1回カウントする必要があります。
あなたの目的のために、数億のうち1つまたは2つがオフになることはあまり重要ではありません。
ここに、そのアイデアを示す簡単なプログラムがあります。エラーチェックはほとんど受けていませんので、自己責任で使用してください。
#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);
}
試してください。http://www.exploringbinary.com/the-spacing-of-decimal-floating-point-numbers/とhttp://www.exploringbinary.com/tag/floating-point/ –
簡単な方法は[std :: nextafter](http://en.cppreference.com/w/cpp/numeric/math/nextafter)を使うことです。 – Incomputable
すべての表現可能な浮動小数点値は有理(無限大、NaNなどを除く)です。 – Peter