0
2

0.1を10回足しても1にならない!?

Last updated at Posted at 2023-12-15

2進法で計算するコンピュータにおいて、10進法で0.1と表される数値を10回足しても1になりません。

丸め誤差

実際、10進法の0.1は無限級数で

\begin{equation}
0.1=2^{-4}\sum_{i=0}^{\infty}a_i2^{-i}
\text{ where }a_i=\begin{cases}1&\text{ if }&i\equiv0,1\mod4\\0&\text{ if }&i\equiv2,3\mod4\end{cases}
\end{equation}

ですが、倍精度浮動小数点数では$i=52$で打ち切ってしまい、

\begin{equation}
0.1=2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-52}+2^{-53}+\dots\right)
\end{equation}

更に、$a_{53}=1$を0捨1入して

\begin{equation}\begin{split}
0.1&=2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-52}+2^{-52}\right)\\
&=2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)
\end{split}\end{equation}

となります(これを丸め誤差といいます)。


情報落ち

今から、

  • 絶対値の大きい方に指数(先頭の$2$の右肩の数)を合わせて足す
  • 仮数部(数式の括弧内)の先頭が$2$になれば指数部を+1
  • 仮数部に$2^{-53}$が残れば$2^{-52}$に切り上げ、それ以降は切り捨て(0捨1入)
    という方針で$0.1+0.1+\dots+0.1$を計算していきます。

まず、これで0.1+0.1を計算すると

\begin{flalign}
0.1+0.1
&=2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-44}+2^{-45}+2^{-48}+2^{-49}+2^{-51}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-44}+2^{-45}+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-4}\left(2+1+2^{-3}+2^{-4}+\dots+2^{-43}+2^{-44}+2^{-47}+2^{-48}+2^{-50}\right)&\\
&=2^{-3}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-44}+2^{-45}+2^{-48}+2^{-49}+2^{-51}\right)&
\end{flalign}

となります。


更に計算を進めていきます。

\begin{flalign}
0.1+0.1+0.1&=(0.1+0.1)+0.1&\\
&=2^{-3}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-3}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&+2^{-3}\left(2^{-1}+2^{-2}+2^{-5}+2^{-6}+\dots+2^{-49}+2^{-50}+2^{-52}\right)&\\
&=2^{-3}\left(2+2^{-2}+2^{-3}+2^{-6}+\dots+2^{-47}+2^{-50}+2^{-51}+2^{-52}\right)&\\
&=2^{-2}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-48}+2^{-51}+2^{-52}+2^{-53}\right)&\\
&\sim2^{-2}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-47}+2^{-48}+2^{-50}\right)&
\end{flalign}

\begin{flalign}
0.1+0.1+0.1+0.1&=(0.1+0.1+0.1)+0.1&\\
&=2^{-2}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-47}+2^{-48}+2^{-50}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-2}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-47}+2^{-48}+2^{-50}\right)&\\
&+2^{-2}\left(2^{-2}+2^{-3}+2^{-6}+2^{-7}+\dots+2^{-50}+2^{-51}+2^{-53}\right)&\\
&=2^{-2}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}+2^{-53}\right)&\\
&\sim2^{-2}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}+2^{-52}\right)&
\end{flalign}

\begin{flalign}
&0.1+0.1+0.1+0.1+0.1=(0.1+0.1+0.1+0.1)+0.1&\\
&=2^{-2}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-2}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&+2^{-2}\left(2^{-2}+2^{-3}+2^{-6}+2^{-7}+\dots+2^{-50}+2^{-51}+2^{-53}\right)&\\
&=2^{-2}\left(1+2^{-1}+2^{-2}+2^{-3}+\dots+2^{-48}+2^{-49}+2^{-50}+2^{-51}+2^{-51}+2^{-53}\right)&\\
&=2^{-2}\left(2+2^{-53}\right)=2^{-1}\left(1+2^{-54}\right)\sim2^{-1}&
\end{flalign}

計算が間違っていなければ、0.1を5回足した結果は0.5に一致しました。


\begin{flalign}
&0.1+0.1+0.1+0.1+0.1+0.1=(0.1+0.1+0.1+0.1+0.1)+0.1&\\
&=2^{-1}+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-1}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-48}+2^{-51}+2^{-52}+2^{-54}\right)&\\
&\sim2^{-1}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-48}+2^{-51}+2^{-52}\right)&\\
\end{flalign}

\begin{flalign}
&0.1+0.1+0.1+0.1+0.1+0.1+0.1=(0.1+0.1+0.1+0.1+0.1+0.1)+0.1&\\
&=2^{-1}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-48}+2^{-51}+2^{-52}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-1}\left(1+2^{-3}+2^{-4}+2^{-7}+\dots+2^{-48}+2^{-51}+2^{-52}\right)&\\
&+2^{-1}\left(2^{-3}+2^{-4}+2^{-7}+2^{-8}+\dots+2^{-51}+2^{-52}+2^{-54}\right)&\\
&=2^{-1}\left(1+2^{-2}+2^{-3}+2^{-6}+2^{-7}+\dots+2^{-50}+2^{-51}+2^{-54}\right)&\\
&\sim2^{-1}\left(1+2^{-2}+2^{-3}+2^{-6}+2^{-7}+\dots+2^{-50}+2^{-51}\right)&\\
\end{flalign}

\begin{flalign}
&0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1\\&=(0.1+0.1+0.1+0.1+0.1+0.1+0.1)+0.1&\\
&=2^{-1}\left(1+2^{-2}+2^{-3}+2^{-6}+2^{-7}+\dots+2^{-50}+2^{-51}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-1}\left(1+2^{-2}+2^{-3}+2^{-6}+2^{-7}+\dots+2^{-50}+2^{-51}\right)&\\
&+2^{-1}\left(2^{-3}+2^{-4}+2^{-7}+2^{-8}+\dots+2^{-51}+2^{-52}+2^{-54}\right)&\\
&=2^{-1}\left(1+2^{-1}+2^{-4}+2^{-5}+2^{-8}+\dots+2^{-48}+2^{-49}+2^{-52}+2^{-54}\right)&\\
&\sim2^{-1}\left(1+2^{-1}+2^{-4}+2^{-5}+2^{-8}+\dots+2^{-48}+2^{-49}+2^{-52}\right)&\\
\end{flalign}

既に、0.1を8倍した値$2^{-1}\left(1+\dots+2^{-51}\right)$と、0.1を8回足した値$2^{-1}\left(1+\dots+2^{-52}\right)$で、$2^{-53}$の誤差が出ていますね。
絶対値の小さい0.1の指数部-4を、絶対値の大きい0.8の指数部-1に合わせた際、仮数部に残った$2^{-54}$が落ちています。これを情報落ちといいます。(この現象はすでに発生している)


\begin{flalign}
&0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1\\&=(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1)+0.1&\\
&=2^{-1}\left(1+2^{-1}+2^{-4}+2^{-5}+2^{-8}+\dots+2^{-48}+2^{-49}+2^{-52}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-1}\left(1+2^{-1}+2^{-4}+2^{-5}+2^{-8}+\dots+2^{-48}+2^{-49}+2^{-52}\right)&\\
&+2^{-1}\left(2^{-3}+2^{-4}+2^{-7}+2^{-8}+\dots+2^{-51}+2^{-52}+2^{-54}\right)&\\
&=2^{-1}\left(1+2^{-1}+2^{-2}+2^{-5}+2^{-6}+\dots+2^{-49}+2^{-50}+2^{-54}\right)&\\
&\sim2^{-1}\left(1+2^{-1}+2^{-2}+2^{-5}+2^{-6}+\dots+2^{-49}+2^{-50}\right)&\\
\end{flalign}

\begin{flalign}
&0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1\\&=(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1)+0.1&\\
&=2^{-1}\left(1+2^{-1}+2^{-2}+2^{-5}+2^{-6}+\dots+2^{-49}+2^{-50}\right)&\\
&+2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&\\
&=2^{-1}\left(1+2^{-1}+2^{-2}+2^{-5}+2^{-6}+\dots+2^{-49}+2^{-50}\right)&\\
&+2^{-1}\left(2^{-3}+2^{-4}+2^{-7}+2^{-8}+\dots+2^{-51}+2^{-52}+2^{-54}\right)&\\
&=2^{-1}\left(1+2^{-1}+2^{-2}+2^{-3}+2^{-4}+\dots+2^{-49}+2^{-50}+2^{-51}+2^{-52}+2^{-54}\right)&\\
&\sim2^{-1}\left(1+2^{-1}+2^{-2}+2^{-3}+2^{-4}+\dots+2^{-49}+2^{-50}+2^{-51}+2^{-52}\right)&\\
\end{flalign}

残念ながら、0.1を10回足した結果は、1より$2^{-1}\times2^{-52}=2^{-53}$だけ少ないことが分かりました(途中の計算が間違っていなければ)。


折角なので、足して1になってほしい浮動小数点数の組み合わせで、誤差をチェックしてみましょう。
以下のsum関数のテストをするつもりで、テストケースを作成します。

#include <stdarg.h>

/*
 * 入力された浮動小数点数の合計値を返す
 * n : 入力する浮動小数点数の個数
 */
double sum(int n,...){
	va_list ap;
	va_start(ap,n);
	double total=0.0;
	for(int i=0;i<n;i++){
		total+=va_arg(ap,double);
	}
	va_end(ap);
	return total;
}

この関数に対して、可変長引数の部分に整数が入力されると、正しく処理されません。1ではなく、1.0(double)1として渡してください。


  • 答えが1になってほしいテストを実施し、テスト結果を表示する
#include <stdio.h>
#include <stdarg.h>
#include <math.h>

/* 総テストケース数 */
int tests_run=0;

/* 成功したテストケース数 */
int success=0;

/*
 * 答えが1になってほしいテストを実施し、テスト結果を表示する
 * n : 入力する値の個数
 * 可変長引数の部分には合計が1となることが期待される浮動小数点数列を入力する
 */
void test(int n,...){
	va_list ap;
	va_start(ap,n);
	
	//入力された浮動小数点数を配列に格納する
	double A[10] = {0};
	for(int i=0;i<n;i++){
		A[i]=va_arg(ap,double);
		
		//入力値を画面表示
		putchar(i?'+':'$');
		printf("%.1lf",A[i]);
	}
	va_end(ap);
	
	//テスト:合計値を計算する※n以上の添字の値は関数呼び出し先で使われない
	double result=sum(n,A[0],A[1],A[2],A[3],A[4],A[5],A[6],A[7],A[8],A[9]);
	tests_run++;
	
	//誤差をm*2^nの形で出力する
	int exponent;
	double mantissa=frexp(result-1,&exponent);
	printf("=1");
	if(mantissa)printf("%+lf\\times2^{%d}",mantissa*2,exponent-1);
 	else success++;
	printf("$\n");
}

  • テストケース
    • 1~24 {0.1,0.2,0.3,0.4}の順列
    • 25~66 小数点以下1桁以下の正の実数値を昇順ソートした数列(絶対値の小さい値から足したほうが精度が上がる)
      ※#1と#47は重複しています。
void test1(){test(4,.1,.2,.3,.4);}
void test2(){test(4,.1,.2,.4,.3);}
void test3(){test(4,.1,.3,.2,.4);}
void test4(){test(4,.1,.3,.4,.2);}
void test5(){test(4,.1,.4,.2,.3);}
void test6(){test(4,.1,.4,.3,.2);}
void test7(){test(4,.2,.1,.3,.4);}
void test8(){test(4,.2,.1,.4,.3);}
void test9(){test(4,.2,.3,.1,.4);}
void test10(){test(4,.2,.3,.4,.1);}
void test11(){test(4,.2,.4,.1,.3);}
void test12(){test(4,.2,.4,.3,.1);}
void test13(){test(4,.3,.1,.2,.4);}
void test14(){test(4,.3,.1,.4,.2);}
void test15(){test(4,.3,.2,.1,.4);}
void test16(){test(4,.3,.2,.4,.1);}
void test17(){test(4,.3,.4,.1,.2);}
void test18(){test(4,.3,.4,.2,.1);}
void test19(){test(4,.4,.1,.2,.3);}
void test20(){test(4,.4,.1,.3,.2);}
void test21(){test(4,.4,.2,.1,.3);}
void test22(){test(4,.4,.2,.3,.1);}
void test23(){test(4,.4,.3,.1,.2);}
void test24(){test(4,.4,.3,.2,.1);}

void test25(){test(1,1.);}
void test26(){test(2,.1,.9);}
void test27(){test(2,.2,.8);}
void test28(){test(3,.1,.1,.8);}
void test29(){test(2,.3,.7);}
void test30(){test(3,.1,.2,.7);}
void test31(){test(4,.1,.1,.1,.7);}
void test32(){test(2,.4,.6);}
void test33(){test(3,.1,.3,.6);}
void test34(){test(3,.2,.2,.6);}
void test35(){test(4,.1,.1,.2,.6);}
void test36(){test(5,.1,.1,.1,.1,.6);}
void test37(){test(2,.5,.5);}
void test38(){test(3,.1,.4,.5);}
void test39(){test(3,.2,.3,.5);}
void test40(){test(4,.1,.1,.3,.5);}
void test41(){test(4,.1,.2,.2,.5);}
void test42(){test(5,.1,.1,.1,.2,.5);}
void test43(){test(6,.1,.1,.1,.1,.1,.5);}
void test44(){test(3,.2,.4,.4);}
void test45(){test(4,.1,.1,.4,.4);}
void test46(){test(3,.3,.3,.4);}
void test47(){test(4,.1,.2,.3,.4);}
void test48(){test(5,.1,.1,.1,.3,.4);}
void test49(){test(4,.2,.2,.2,.4);}
void test50(){test(5,.1,.1,.2,.2,.4);}
void test51(){test(6,.1,.1,.1,.1,.2,.4);}
void test52(){test(7,.1,.1,.1,.1,.1,.1,.4);}
void test53(){test(4,.1,.3,.3,.3);}
void test54(){test(4,.2,.2,.3,.3);}
void test55(){test(5,.1,.1,.2,.3,.3);}
void test56(){test(6,.1,.1,.1,.1,.3,.3);}
void test57(){test(5,.1,.2,.2,.2,.3);}
void test58(){test(6,.1,.1,.1,.2,.2,.3);}
void test59(){test(7,.1,.1,.1,.1,.1,.2,.3);}
void test60(){test(8,.1,.1,.1,.1,.1,.1,.1,.3);}
void test61(){test(5,.2,.2,.2,.2,.2);}
void test62(){test(6,.1,.1,.2,.2,.2,.2);}
void test63(){test(7,.1,.1,.1,.1,.2,.2,.2);}
void test64(){test(8,.1,.1,.1,.1,.1,.1,.2,.2);}
void test65(){test(9,.1,.1,.1,.1,.1,.1,.1,.1,.2);}
void test66(){test(10,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1);}

  • main関数
int main(int argc, char* argv[]){
	test1();
	test2();
	test3();
	test4();
	test5();
	test6();
	test7();
	test8();
	test9();
	test10();
	test11();
	test12();
	test13();
	test14();
	test15();
	test16();
	test17();
	test18();
	test19();
	test20();
	test21();
	test22();
	test23();
	test24();
	test25();
	test26();
	test27();
	test28();
	test29();
	test30();
	test31();
	test32();
	test33();
	test34();
	test35();
	test36();
	test37();
	test38();
	test39();
	test40();
	test41();
	test42();
	test43();
	test44();
	test45();
	test46();
	test47();
	test48();
	test49();
	test50();
	test51();
	test52();
	test53();
	test54();
	test55();
	test56();
	test57();
	test58();
	test59();
	test60();
	test61();
	test62();
	test63();
	test64();
	test65();
	test66();
	printf("success...%d/%d\n",success,tests_run);
	return 0;
}

  • 出力結果
    test関数にてわざと$記号付きで出力したものをそのまま貼り付けているので、Markdown記法では数式のように表示されています。

$0.1+0.2+0.3+0.4=1$
$0.1+0.2+0.4+0.3=1$
$0.1+0.3+0.2+0.4=1$
$0.1+0.3+0.4+0.2=1$
$0.1+0.4+0.2+0.3=1$
$0.1+0.4+0.3+0.2=1$
$0.2+0.1+0.3+0.4=1$
$0.2+0.1+0.4+0.3=1$
$0.2+0.3+0.1+0.4=1$
$0.2+0.3+0.4+0.1=1$
$0.2+0.4+0.1+0.3=1$
$0.2+0.4+0.3+0.1=1+1.000000\times2^{-52}$
$0.3+0.1+0.2+0.4=1$
$0.3+0.1+0.4+0.2=1$
$0.3+0.2+0.1+0.4=1$
$0.3+0.2+0.4+0.1=1$
$0.3+0.4+0.1+0.2=1$
$0.3+0.4+0.2+0.1=1-1.000000\times2^{-53}$
$0.4+0.1+0.2+0.3=1$
$0.4+0.1+0.3+0.2=1$
$0.4+0.2+0.1+0.3=1$
$0.4+0.2+0.3+0.1=1+1.000000\times2^{-52}$
$0.4+0.3+0.1+0.2=1$
$0.4+0.3+0.2+0.1=1-1.000000\times2^{-53}$
$1.0=1$
$0.1+0.9=1$
$0.2+0.8=1$
$0.1+0.1+0.8=1$
$0.3+0.7=1$
$0.1+0.2+0.7=1$
$0.1+0.1+0.1+0.7=1$
$0.4+0.6=1$
$0.1+0.3+0.6=1$
$0.2+0.2+0.6=1$
$0.1+0.1+0.2+0.6=1$
$0.1+0.1+0.1+0.1+0.6=1$
$0.5+0.5=1$
$0.1+0.4+0.5=1$
$0.2+0.3+0.5=1$
$0.1+0.1+0.3+0.5=1$
$0.1+0.2+0.2+0.5=1$
$0.1+0.1+0.1+0.2+0.5=1$
$0.1+0.1+0.1+0.1+0.1+0.5=1$
$0.2+0.4+0.4=1$
$0.1+0.1+0.4+0.4=1$
$0.3+0.3+0.4=1$
$0.1+0.2+0.3+0.4=1$
$0.1+0.1+0.1+0.3+0.4=1$
$0.2+0.2+0.2+0.4=1$
$0.1+0.1+0.2+0.2+0.4=1$
$0.1+0.1+0.1+0.1+0.2+0.4=1$
$0.1+0.1+0.1+0.1+0.1+0.1+0.4=1$
$0.1+0.3+0.3+0.3=1$
$0.2+0.2+0.3+0.3=1$
$0.1+0.1+0.2+0.3+0.3=1$
$0.1+0.1+0.1+0.1+0.3+0.3=1$
$0.1+0.2+0.2+0.2+0.3=1$
$0.1+0.1+0.1+0.2+0.2+0.3=1$
$0.1+0.1+0.1+0.1+0.1+0.2+0.3=1$
$0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.3=1$
$0.2+0.2+0.2+0.2+0.2=1$
$0.1+0.1+0.2+0.2+0.2+0.2=1$
$0.1+0.1+0.1+0.1+0.2+0.2+0.2=1$
$0.1+0.1+0.1+0.1+0.1+0.1+0.2+0.2=1$
$0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.2=1$
$0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1=1-1.000000\times2^{-53}$
success...61/66

前半24個のテストケースより、絶対値の小さい値を最後に足してしまうと、誤差が発生しやすくなることが分かります。

けた落ち

ついでに、$0.9-0.8$と$0.1$を比較してみたいと思います

\begin{flalign}
0.9
&=2^{-1}\left(1+2^{-1}+2^{-2}+2^{-5}+2^{-6}+\dots+2^{-45}+2^{-46}+2^{-49}+2^{-50}+2^{-52}\right)&\\
0.8
&=2^{-1}\left(1+2^{-1}+2^{-4}+2^{-5}+2^{-8}+\dots+2^{-44}+2^{-45}+2^{-48}+2^{-49}+2^{-51}\right)&\\
0.9-0.8&=2^{-1}\left(2^{-3}+2^{-4}+2^{-7}+2^{-8}+\dots+2^{-47}+2^{-48}+2^{-51}+2^{-52}\right)&\\
&=2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-44}+2^{-45}+2^{-48}+2^{-49}\right)&\\
\end{flalign}

一方、

\begin{flalign}
&0.1=2^{-4}\left(1+2^{-1}+2^{-4}+2^{-5}+\dots+2^{-48}+2^{-49}+2^{-51}\right)&
\end{flalign}

なので、$0.9-0.8$は$0.1$より$2^{-55}$小さい値となりました。
$0.9-0.8$を計算する際、指数部が元々-1だったのが-4になったことにより、2進法での有効桁数が3桁落ちています。これをけた落ちといいます。

#include <stdio.h>
#include <math.h>

int main(int argc, char* argv[]){
	double x=.9;
	x-=.8;
	int exponent;
	double mantissa=frexp(x-.1,&exponent);
	printf("$0.9-0.8=0.1%+lf\\times2^{%d}$\n",mantissa*2,exponent-1);
	return 0;
}

実行結果
$0.9-0.8=0.1-1.000000\times2^{-55}$
※実行環境によって、$0.9-0.8$と$0.1$は等しくなることがあります。

  • 言語によってはDecimal型のような十進法で扱う型があります。より正確に計算したい場合はそちらを使うようにしましょう。
0
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2