実数の表示

桁数があまりにも長いと「10桁ずつに区切って表示したい」ということもあります。 そのようなときは結果をコピーして他のプログラミング(例えばC#)を使って編集すると 良いのですが、このくらいの文字列処理ならばmaximaでも可能です。

小数部分を「d桁ずつ」と「fp桁」まで表示する関数.(ただし x>0 とする)

PrintDecimal(x,d,fp):=block(
    [IntegerPart,FractionalPart,max],
    max:quotient(fp,d),
    fpprec:fp+5, /* すこし余分に求めておく */
    IntegerPart:string(floor(x)),
    FractionalPart:sremove(".",string(bfloat(x-floor(x)))),
    print("Integer part is",IntegerPart),
    print("Fractional part is as follows:"),
    for i:0 thru max-1 do (
        block(
            [t1],
            t1:substring(FractionalPart,1+i*d,1+(i+1)*d),
            print(i*d+1,~,(i+1)*d,":",t1)
        )
    )
)$
PrintDecimal(%pi,5,30); /*円周率を小数点以下5桁ずつ30桁まで表示.*/

実行結果.

Integer part is 3 
Fractional part is as follows: 
1 ~ 5 : 14159 
6 ~ 10 : 26535 
11 ~ 15 : 89793 
16 ~ 20 : 23846 
21 ~ 25 : 26433 
26 ~ 30 : 83279 

maximaの実行結果をコピペすると無駄なダブルクォーテーションが発生してしまうことがあります。 これを回避したものが次のコードです。

小数点以下をコピペしやすいようにしたもの.

PrintDecimal(x,d,fp):=block(
    [IntegerPart,FractionalPart,max,result:""],
    max:quotient(fp,d),
    fpprec:fp+5, /* すこし余分に求めておく */
    IntegerPart:string(floor(x)),
    FractionalPart:sremove(".",string(bfloat(x-floor(x)))),
    print("Integer part is",IntegerPart),
    print("Fractional part is as follows:"),
    for i:0 thru max-1 do (
        block(
            [t1],
            t1:substring(FractionalPart,1+i*d,1+(i+1)*d),
            result:sconcat(result,printf(false,"~a ~~ ~a:~a ~%",i*d+1,(i+1)*d,t1))
        )
    ),
    result
)$
PrintDecimal(%pi,5,30);

実行結果.

Integer part is 3
Fractional part is as follows:
1 ~ 5:14159 
6 ~ 10:26535 
11 ~ 15:89793 
16 ~ 20:23846 
21 ~ 25:26433 
26 ~ 30:83279 

解説.

「~%」というのが改行を意味します。maximaの実行結果にはこの改行がなぜか反映されないのですがコピペすると ちゃんと改行が挿入されることがわかります。これでも結局無駄なダブルクォーテーションが出ますが、前のコードよりはずいぶんマシです。