変数の型にはそれぞれ扱える値の上限がありますが、精度にも上限があります。この上限が何を意味するのか実際に見てみましょう。
まず、intで扱える最大値は 2147483647 なので、479001600(=12!)に13をかけると(これが13!)、この上限を超えます。このときなぜエラーにならず間違った答がでるかはともかく、12!まで正しく計算できます。
longでは 9223372036854775807 が上限ですから、20!=2432902008176640000 までを正しく計算できます。
double ではもっと先まで計算できますが、細かなところで誤差が出ています。( doubleで計算すると大きな値の表示が 3.99168E7 のように E 付きの表示になりますが、真の値との比較のため書き直しています)
n | intで計算 | longで計算 | doubleで計算 | 真の値 |
---|---|---|---|---|
1 | 1 | 1 | 1 | 1 |
2 | 2 | 2 | 2 | 2 |
3 | 6 | 6 | 6 | 6 |
4 | 24 | 24 | 24 | 24 |
5 | 120 | 120 | 120 | 120 |
6 | 720 | 720 | 720 | 720 |
7 | 5040 | 5040 | 5040 | 5040 |
8 | 40320 | 40320 | 40320 | 40320 |
9 | 362880 | 362880 | 362880 | 362880 |
10 | 3628800 | 3628800 | 3628800 | 3628800 |
11 | 39916800 | 39916800 | 39916800 | 39916800 |
12 | 479001600 | 479001600 | 479001600 | 479001600 |
13 | 1932053504 | 6227020800 | 6227020800 | 6227020800 |
14 | 1278945280 | 87178291200 | 87178291200 | 87178291200 |
15 | 2004310016 | 1307674368000 | 1307674368000 | 1307674368000 |
16 | 2004189184 | 20922789888000 | 20922789888000 | 20922789888000 |
17 | -288522240 | 355687428096000 | 355687428096000 | 355687428096000 |
18 | -898433024 | 6402373705728000 | 6402373705728000 | 6402373705728000 |
19 | 109641728 | 121645100408832000 | 121645100408832000 | 121645100408832000 |
20 | -2102132736 | 2432902008176640000 | 2432902008176640000 | 2432902008176640000 |
21 | -1195114496 | -4249290049419214848 | 51090942171709440000 | 51090942171709440000 |
22 | -522715136 | -1250660718674968576 | 1124000727777607700000 | 1124000727777607680000 |
23 | 862453760 | 8128291617894825984 | 25852016738884980000000 | 25852016738884976640000 |
背景色のある所は正しくない部分です。
double についてだけもう少し大きな n まで見てみると、次のようになります。
つまり double では最初の16桁までは計算してそれ以降は計算していないのです。これが計算精度(計算の細かさ・正確さ)の上限です。double は long より大きな数を扱うことができますが、その代わり計算精度を犠牲にしているわけです。
n | doubleで計算 | 真の値 |
---|---|---|
24 | 620448401733239400000000 | 620448401733239439360000 |
25 | 15511210043330986000000000 | 15511210043330985984000000 |
26 | 403291461126605650000000000 | 403291461126605635584000000 |
27 | 10888869450418352000000000000 | 10888869450418352160768000000 |
28 | 304888344611713840000000000000 | 304888344611713860501504000000 |
29 | 8841761993739701000000000000000 | 8841761993739701954543616000000 |
30 | 265252859812191030000000000000000 | 265252859812191058636308480000000 |
31 | 8222838654177922000000000000000000 | 8222838654177922817725562880000000 |
32 | 263130836933693500000000000000000000 | 263130836933693530167218012160000000 |
33 | 8683317618811886000000000000000000000 | 8683317618811886495518194401280000000 |
34 | 295232799039604120000000000000000000000 | 295232799039604140847618609643520000000 |
35 | 10333147966386144000000000000000000000000 | 10333147966386144929666651337523200000000 |
36 | 371993326789901200000000000000000000000000 | 371993326789901217467999448150835200000000 |
37 | 13763753091226343000000000000000000000000000 | 13763753091226345046315979581580902400000000 |
38 | 523022617466601000000000000000000000000000000 | 523022617466601111760007224100074291200000000 |
39 | 20397882081197442000000000000000000000000000000 | 20397882081197443358640281739902897356800000000 |
40 | 815915283247897700000000000000000000000000000000 | 815915283247897734345611269596115894272000000000 |
double では大きな値は 39916800 となるところを 3.99168E7 と表します。これはもちろん長くならないようにとか、0 がやたら多いと読めないということもありますが、8の後の00の部分が本当に00かどうかは計算していないというのも理由のひとつです。
bouble にも扱える数の最大値があります。それは E の後の数が int のように上限があるからです。
ただし、int や long のように間違った値になるのではなく、Infinity(無限大) となって計算を続けます。もちろん Infinity を2倍しても Infinity ですから、計算が正しいわけではありませんが。
n | double | 真の値 |
---|---|---|
160 | 4.714723635992059E284 | 471472363599206132240694321176194377951192623045460204976904578317542573467421580346978030238114995699562728104819596262106947389303901748942909887857509625114880781313585012959529941660203611234871833992565791817698209861793313332044734813700096000000000000000000000000000000000000000 |
161 | 7.590705053947215E286 | 75907050539472187290751785709367294850142012310319093001281637109124354328254874435863462868336514307629599224875954998199218529677928181579808491945059049643495805791487187086484320607292781408814365272803092482649411787748723446459202305005715456000000000000000000000000000000000000000 |
162 | 1.2296942187394488E289 | 12296942187394494341101789284917501765723005994271693066207625211678145401177289658609880984670515317835995074429904709708273401807824365415928975695099566042246320538220924308010459938381430588227927174194100982189204709615293198326390773410925903872000000000000000000000000000000000000000 |
163 | 2.0044015765453015E291 | 2004401576545302577599591653441552787812849977066285969791842909503537700391898214353410600501293996807267197132074467682448564494675371562796423038301229264886150247730010662205704969956173185881152129393638460096840367667292791327201696065980922331136000000000000000000000000000000000000000 |
164 | 3.2872185855342945E293 | 328721858553429622726333031164414657201307396238870899045862237158580182864271307153959338482212215476391820329660212699921564577126760936298613378281401599441328640627721748601735615072812402484508949220556707455881820297436017777661078154820871262306304000000000000000000000000000000000000000 |
165 | 5.423910666131586E295 | 54239106661315887749844950142128418438215720379413698342567269131165730172604765680403290849565015553604650354393935095487058155225915554489271207416431263907819225703574088519286376487014046409943976621391856730220500349076942933314077895545443758280540160000000000000000000000000000000000000000 |
166 | 9.003691705778433E297 | 9003691705778437366474261723593317460743809582982673924866166675773511208652391102946946281027792581898371958829393225850851653767501982045219020431127589808697991466793298694201538496844331704050700119151048217216603057946772526930136930660543663874569666560000000000000000000000000000000000000000 |
167 | 1.5036165148649983E300 | 1503616514864999040201201707840084015944216200358106545452649834854176371844949314192140028931641361177028117124508668717092226179172831001551576411998307498052564574954480881931656928973003394576466919898225052275172710677111011997332867420310791867053134315520000000000000000000000000000000000000000 |
168 | 2.526075744973197E302 | 252607574497319838753801886917134114678628321660161899636045172255501630469951484784279524860515748677740723676917456344471493998101035608260664837215715659672830848592352788164518364067464570288846442542901808782229015393754650015551921726612213033664926565007360000000000000000000000000000000000000000 |
169 | 4.2690680090047027E304 | 42690680090047052749392518888995665380688186360567361038491634111179775549421800928543239701427161526538182301399050122215682485679075017796052357489455946484708413412107621199803603527401512378815048789750405684196703601544535852628274771797464002689372589486243840000000000000000000000000000000000000000 |
170 | 7.257415615307994E306 | 7257415615307998967396728211129263114716991681296451376543577798900561843401706157852350749242617459511490991237838520776666022565442753025328900773207510902400430280058295603966612599658257104398558294257568966313439612262571094946806711205568880457193340212661452800000000000000000000000000000000000000000 |
171 | Infinity | 1241018070217667823424840524103103992616605577501693185388951803611996075221691752992751978120487585576464959501670387052809889858690710767331242032218484364310473577889968548278290754541561964852153468318044293239598173696899657235903947616152278558180061176365108428800000000000000000000000000000000000000000 |
172 | Infinity | 213455108077438865629072570145733886730056159330291227886899710221263324938130981514753340236723864719151973034287306573083301055694802251980973629541579310661401455397074590303866009781148657954570396550703618437210885875866741044575478989978191912006970522334798649753600000000000000000000000000000000000000000 |
いちばん大きな値を計算できるdoubleに限界があるならどうやって真の値を計算したのでしょうか。いろいろな方法があるのですが、javaには大きな数を計算するための「クラス」が用意されています。これは基本的な変数の型ではありませんが、あたかもBigDecimalという型の変数があるかのように使えるのがjavaです。
詳しい説明は授業が進めば見えてきます。
import java.math.*; public class Kaijou2 { public static void main( String[] args ) { int n = 172; BigDecimal s = new BigDecimal("1"); for( int i=1; i<=n; i++ ) { s = s.multiply( BigDecimal.valueOf(i) ); System.out.print( i ); System.out.print( "! = " ); System.out.println( s ); } } }