• 検索結果がありません。

浮動小数点演算の例(倍精度浮動小数点

N/A
N/A
Protected

Academic year: 2021

シェア "浮動小数点演算の例(倍精度浮動小数点"

Copied!
10
0
0

読み込み中.... (全文を見る)

全文

(1)

● 講義資料

▼ サンプルプログラム

計算機内部の浮動小数演算では,我々の通常の感覚とは異った計算になることがある. この例では0.1 10回加えても1.0にならないことがわかる.

【C (1)】

/*******************************

* $Id: ex_01_01.c,v 1.2 2006-04-10 13:37:00+09 naito Exp $

* 浮動小数点演算の例(倍精度浮動小数点)

* 0.1 10 回加えても 1.0 にはならない

*******************************/

#include <stdio.h>

int main(int argc, char **argv) {

double x = 0.1, y = 0.0 ;

int n ;

for(n=0;n<10;n++) y += x ; printf("y = %f\n", y) ;

if (y == 1.0) printf ("y equals to 1.0\n") ; else printf ("y does not equals to 1.0\n") ; printf("y = %.16f\n", y) ;

return 0 ; }

コンパイル・実行方法

gcc ex_01_01.c -o ex_01_01 ./ex_01_01

結果

y = 1.000000

y does not equals to 1.0 y = 0.9999999999999999 注意事項

doubleは「倍精度浮動小数点型」である.

「単精度浮動小数点型」は floatである.

(2)

【C (2)】

/*******************************

* $Id: ex_01_01_1.c,v 1.3 2006-04-10 13:37:07+09 naito Exp $

* 浮動小数点演算の例(単精度浮動小数点)

* 0.1 10 回加えても 1.0 にはならない

*******************************/

#include <stdio.h>

int main(int argc, char **argv) {

float x = 0.1F, y = 0.0F ;

int n ;

for(n=0;n<10;n++) y += x ; printf("y = %f\n", y) ;

if (y == 1.0F) printf ("y equals to 1.0\n") ; else printf ("y does not equals to 1.0\n") ; printf("y = %.8f\n", y) ;

return 0 ; }

結果

y = 1.000000

y does not equals to 1.0 y = 1.00000012

注意事項

倍精度浮動小数点演算では 0.1 10回加算しても1.0よりも小さな値となる.

単精度浮動小数点演算では 0.1 10回加算したら1.0よりも大きな値となる.

▼ サンプルプログラムのまとめ

0.110回加算しても1.0と等しくはならない.

この計算は, 「言語」や「実行する機器」には依存せず,浮動小数点演算の精度のみに依存した結果 となる. (正確には「丸めモード」には依存している.

単精度浮動小数点演算で 0.110 回加算すると1.0よりもわずかに大きくなり, 倍精度浮動小数 点演算で 0.1 10回加算すると1.0よりもわずかに小さくなる.

(3)

▼ いくつかの数値の計算

ここでは,今後の授業のイントロダクションとして,いくつかの数値を簡単に(手抜きで)計算するプロ グラムを紹介する. これらの計算方法およびその問題点は,今後の授業の中で解説する.

2の平方根の値の計算

【区間縮小法】

/*

* SQRT[2] の値を近似的に求める. 方法1: 区間縮小法

*/

#include <stdio.h>

#include <math.h>

#define N (20)

int main(int argc, char **argv) {

double left, right, sqrt2 ; int i ;

left = 0.0 ; right = 2.0 ; for(i=0;i<N;i++) {

sqrt2 = (left + right)/2.0 ;

printf("%.15f\t%.15e\n", sqrt2, fabs(sqrt2-M_SQRT2)) ; if (sqrt2*sqrt2 <= 2.0) left = sqrt2 ;

else right = sqrt2 ; }

return 0 ; }

1.000000000000000 4.142135623730951e-01 1.500000000000000 8.578643762690485e-02 1.250000000000000 1.642135623730951e-01 1.375000000000000 3.921356237309515e-02 1.437500000000000 2.328643762690485e-02 1.406250000000000 7.963562373095145e-03 1.421875000000000 7.661437626904855e-03 1.414062500000000 1.510623730951455e-04 1.417968750000000 3.755187626904855e-03 1.416015625000000 1.802062626904855e-03 1.415039062500000 8.255001269048545e-04 1.414550781250000 3.372188769048545e-04 1.414306640625000 9.307825190485453e-05 1.414184570312500 2.899206059514547e-05 1.414245605468750 3.204309565485453e-05 1.414215087890625 1.525517529854525e-06

(4)

【ニュートン法】

/*

* SQRT[2] の値を近似的に求める. 方法2: ニュートン法

*/

#include <stdio.h>

#include <math.h>

#define N (8)

int main(int argc, char **argv) {

double sqrt2 ; int i ;

sqrt2 = 2.0 ; for(i=0;i<N;i++) {

printf("%.15f\t%.15e\n", sqrt2, fabs(sqrt2-M_SQRT2)) ; sqrt2 = sqrt2/2.0 + 1.0/sqrt2 ;

}

return 0 ; }

2.000000000000000 5.857864376269049e-01 1.500000000000000 8.578643762690485e-02 1.416666666666667 2.453104293571373e-03 1.414215686274510 2.123901414519125e-06 1.414213562374690 1.594724352571575e-12 1.414213562373095 2.220446049250313e-16 1.414213562373095 2.220446049250313e-16 1.414213562373095 2.220446049250313e-16

(5)

★ 自然対数の底の値の計算

【定義をそのまま計算】

/*

* 自然対数の底 $e$ の値を近似的に求める. 方法1の1: (1+1/n)^n の値を計算する. ひたす らかけ算する.

*/

#include <stdio.h>

#include <math.h>

double calc_e(unsigned long n) ; unsigned long n[] = {

10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL, 1000000000UL, 10000000000UL, 100000000000UL } ;

int main(int argc, char **argv) {

int i, m ; double e ;

m = sizeof(n)/sizeof(unsigned long) ; for(i=0;i<m;i++) {

e = calc_e(n[i]) ;

printf("%lu\t%.15f\t%.15e\n", n[i], e, fabs(e-M_E)) ; }

return 0 ; }

double calc_e(unsigned long n) { double x = 1.0 ;

double y ;

unsigned long int i ; y = 1.0 + 1.0/n ;

for(i=0UL;i<n;i++) x *= y ; return x ;

}

10 2.593742460100002 1.245393683590428e-01 100 2.704813829421529 1.346799903751572e-02 1000 2.716923932235598 1.357896223446620e-03 10000 2.718145926824898 1.359016341466734e-04 100000 2.718268237192295 1.359126675026801e-05 1000000 2.718280469095936 1.359363108743850e-06

10000000 2.718281694132010 1.343270348286296e-07

(6)

【テイラー展開を利用する】

/*

* 自然対数の底 $e$ の値を近似的に求める. 方法2の1: exp(x) のテイラー展開を計算する.

*/

#include <stdio.h>

#include <math.h>

unsigned long n[] = { 5UL, 10UL, 20UL, 30UL, } ;

double calc_e(unsigned long n) ; int main(int argc, char **argv) {

int i, m ; double e ;

m = sizeof(n)/sizeof(unsigned long) ; for(i=0;i<m;i++) {

e = calc_e(n[i]) ;

printf("%lu\t%.15f\t%.15e\n", n[i], e, fabs(e-M_E)) ; }

return 0 ; }

double calc_e(unsigned long n) { double x = 1.0 ;

double y = 1.0 ; unsigned long int i ;

for(i=1UL;i<n;i++) { y *= 1.0/(double)i ; x += y ;

}

return x ; }

5 2.708333333333333 9.948495125712054e-03 10 2.718281525573192 3.028858528431044e-07 20 2.718281828459046 4.440892098500626e-16 30 2.718281828459046 4.440892098500626e-16

(7)

★ 円周率の値の計算

【内接正多角形の長さを利用】

/*

* 円周率 $pi$ の値を近似的に求める. 方法3の1: 多角形近似. 単なる倍角の公式.

*/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <math.h>

#define N (20)

unsigned long pi_montecalro(unsigned long n) ; int main(int argc, char **argv)

{

int i ;

unsigned long n ; unsigned int p ; double pi ; double inner ; inner = 3.0 ; for(i=0;i<N;i++) {

n = (1UL<<i)*6 ;

printf("%lu\t%.15f\t%.15e\n", (1UL<<i)*6, inner, fabs(inner-M_PI)) ; inner = 2*n*sqrt((1.0 - sqrt(1.0-(inner/n)*(inner/n)))/2.0) ;

}

return 0 ; }

6 3.000000000000000 1.415926535897931e-01 12 3.105828541230250 3.576411235954335e-02 24 3.132628613281237 8.964040308556243e-03 48 3.139350203046872 2.242450542921048e-03 96 3.141031950890530 5.607026992633379e-04 192 3.141452472285344 1.401813044488165e-04 384 3.141557607911622 3.504567817103066e-05 768 3.141583892148936 8.761440857263381e-06 1536 3.141590463236762 2.190353031394920e-06 3072 3.141592106043048 5.475467448334825e-07 6144 3.141592516588155 1.370016384782957e-07 12288 3.141592618640789 3.494900369105380e-08 24576 3.141592645321216 8.268577378345299e-09 49152 3.141592645321216 8.268577378345299e-09 98304 3.141592645321216 8.268577378345299e-09 196608 3.141592645321216 8.268577378345299e-09

(8)

【テイラー展開を利用する】

/*

* 円周率 $pi$ の値を近似的に求める. 方法1の1: arctan(x) のテイラー展開を x = 1 で求 める.

*/

#include <stdio.h>

#include <math.h>

unsigned long n[] = {

10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL } ;

double atan_taylor(unsigned long n, double x) ; int main(int argc, char **argv)

{

int i, m ; double pi ;

m = sizeof(n)/sizeof(unsigned long) ; for(i=0;i<m;i++) {

pi = atan_taylor(n[i], 1.0)*4.0 ;

printf("%lu\t%.15f\t%.15e\n", n[i], pi, fabs(pi-M_PI)) ; }

return 0 ; }

double atan_taylor(unsigned long n, double x) { double v = 0.0 ;

double y ;

unsigned long int i ; int sign = 1 ;

y = x ;

for(i=1UL;i<n;i+=2) {

if (sign) v += (1.0/(double)i) * y ; else v -= (1.0/(double)i) * y ; y *= x*x ;

sign ^= 1 ; }

return v ; }

10 3.339682539682540 1.980898860927471e-01 100 3.121594652591011 1.999800099878213e-02 1000 3.139592655589785 1.999998000008052e-03 10000 3.141392653591791 1.999999980020206e-04 100000 3.141572653589781 2.000000001167734e-05 1000000 3.141590653589692 2.000000101087807e-06

10000000 3.141592453589780 2.000000134394497e-07

(9)

【注意0】 情報メディア教育センターの MacOSXでは, Cコンパイラ利用時には-m64オプションをつ けると, long,unsigned long 8バイトとなります.

gcc -m64 foo.c

とする. (-m64がついていることに注意.

【注意1】 Cにおいて powなどの「数学関数ライブラリ」を用いる場合には,

gcc foo.c -lm

または

gcc -m64 foo.c -lm

とする. (-lmがついていることに注意.)代表的な数学関数は以下の通り.

acos arc cosine function

acosh inverse hyperbolic cosine function asin arc sine function

asinh hyperbolic sine function atan arc tangent function

atanh inverse hyperbolic tangent function ceil ceiling value function

cos cosine function

cosh hyperbolic cosine function exp exponential function fabs absolute value function floor floor function

log natural logarithm function

pow power function

sin sine function

sinh hyperbolic sine function sqrt square root function

tan tangent function

tanh hyperbolic tangent function

【注意2】 math.hの中では,以下の数学定数の値が浮動小数点定数として定義されている.

M_E The base of natural logarithms (e).

M_LOG2E The base-2 logarithm of e.

(10)

M_PI pi, the ratio of the circumference of a circle to its diameter.

M_PI_2 pi/2.

M_PI_4 pi/4.

M_1_PI 1/pi.

M_2_PI 2/pi.

M_2_SQRTPI 2 over the square root of pi.

M_SQRT2 The positive square root of 2.

M_SQRT1_2 The positive square root of 1/2.

【注意3】 この授業の実習・課題やレポートの回答では,「IEEE754浮動小数点演算標準」に準拠してい る言語であれば,何を使っても構わないこととする. (C, Java, Fortran, OCamlなどはこれに該当す る.)

参照

関連したドキュメント

Our first result is a lattice path interpretation of the double Schur function based on a flagged determinantal formula derived from a formula of Lascoux for the symmetric

It is assumed that the reader is familiar with the standard symbols and fundamental results of Nevanlinna theory, as found in [5] and [15].. Rubel and C.C. Zheng and S.P. Wang [18],

The period function near such intermediate closed orbits, in both the generic and non-generic case, will be studied using techniques from [6, 8], where small-amplitude limit cycles

Gill’s result [7] applied to Thue equations, yields that the height of the solutions are bounded. [14]) considered the problem to determine effectively all solu- tions of a given

ELMAHI, An existence theorem for a strongly nonlinear elliptic prob- lems in Orlicz spaces, Nonlinear Anal.. ELMAHI, A strongly nonlinear elliptic equation having natural growth

Koo, On Relations Between Eisenstein Series, Dedekind Eta Function Theta Functions and Elliptic Analogue of The Hardy Sums, sunbmitted..

Asymptotic expansions of iterates of …ve functions, namely, the logarithmic function, the inverse tangent function, the inverse hyperbolic sine function, the hyperbolic tangent

Guo, “A class of logarithmically completely monotonic functions and the best bounds in the second Kershaw’s double inequality,” Journal of Computational and Applied Mathematics,