私はdouble
値を持っており、元の値f
にできるだけ近いが元の値よりも厳密に大きい (または小さい) 新しい値を取得するために、値をわずかに大きく (または小さく) 微調整する方法が必要です。
最後のビットに近づく必要はありません。どのような変更を行っても、異なる値が生成され、元の値に丸められないことが保証されることがより重要です。
私はdouble
値を持っており、元の値f
にできるだけ近いが元の値よりも厳密に大きい (または小さい) 新しい値を取得するために、値をわずかに大きく (または小さく) 微調整する方法が必要です。
最後のビットに近づく必要はありません。どのような変更を行っても、異なる値が生成され、元の値に丸められないことが保証されることがより重要です。
math.h ファイルを確認してください。運が良ければ、 関数nextafter
とnextafterf
関数が定義されています。それらは、ポータブルでプラットフォームに依存しない方法で、まさにあなたが望むことを行い、C99 標準の一部です。
それを行う別の方法(フォールバックソリューションになる可能性があります)は、浮動小数点数を仮数部と指数部に分解することです。増分は簡単です。仮数に 1 を追加するだけです。オーバーフローが発生した場合は、指数をインクリメントしてこれを処理する必要があります。デクリメントも同じように機能します。
編集:コメントで指摘されているように、バイナリ表現でフロートをインクリメントするだけで十分です。仮数オーバーフローは指数をインクリメントします。これがまさに私たちが望んでいることです。
それは一言で言えば nextafter と同じことです。
ただし、これは完全に移植可能ではありません。エンディアンと、すべてのマシンが IEEE float を持っているわけではないという事実に対処する必要があります (わかりました - 最後の理由はよりアカデミックです)。
また、NAN と無限の処理は少し難しい場合があります。数値ではなく定義上、単純にインクリメントすることはできません。
u64 &x = *(u64*)(&f);
x++;
はい、真剣に。
編集:誰かが指摘したように、これは -ve 番号、Inf、Nan、またはオーバーフローを適切に処理しません。上記のより安全なバージョンは
u64 &x = *(u64*)(&f);
if( ((x>>52) & 2047) != 2047 ) //if exponent is all 1's then f is a nan or inf.
{
x += f>0 ? 1 : -1;
}
私はまったく同じことをする必要があり、このコードを思いついた:
double DoubleIncrement(double value)
{
int exponent;
double mantissa = frexp(value, &exponent);
if(mantissa == 0)
return DBL_MIN;
mantissa += DBL_EPSILON/2.0f;
value = ldexp(mantissa, exponent);
return value;
}
これはまさにあなたが望むものではないかもしれませんが、numeric_limitsが使用されていることに気付くかもしれません。特に、メンバー min() と epsilon() です。
mydouble + numeric_limits::epsilon() のようなものが、mydouble がすでにイプシロンに近づいていない限り、あなたが望むことをするとは思いません。もしそうなら、あなたは幸運です。
参考までに、標準の ++ インクリメントが機能しなくなる値は 9,007,199,254,740,992 です。
しばらく前にこのコードを見つけました。おそらく、それまでに押し上げることができる最小値を決定し、その値だけインクリメントするのに役立つでしょう。残念ながら、このコードのリファレンスを思い出せません:
#include <stdio.h>
int main()
{
/* two numbers to work with */
double number1, number2; // result of calculation
double result;
int counter; // loop counter and accuracy check
number1 = 1.0;
number2 = 1.0;
counter = 0;
while (number1 + number2 != number1) {
++counter;
number2 = number2 / 10;
}
printf("%2d digits accuracy in calculations\n", counter);
number2 = 1.0;
counter = 0;
while (1) {
result = number1 + number2;
if (result == number1)
break;
++counter;
number2 = number2 / 10.0;
}
printf("%2d digits accuracy in storage\n", counter );
return (0);
}