実数計算はできるけど、計算結果の表示はできない?
SDCCにはfloat型(しかもIEEE形式)の実数演算機能が備わっています。doubleはさすがにありません。
#include <stdarg.h>
#include <stdio.h>
void (*wexit)() = (void *)0x0083 ;
void (*conout)(char) = (void *)0x008c ;
int putchar(int c)
{
if (c == '\n')
conout('\r') ;
conout(c) ;
return c ;
}
void main()
{
int i ;
float x = 0.123 ;
for (i = 0; i < 10; i++) {
printf("i = %d, %f\n", i, x*i) ;
}
wexit() ; // プログラムの終了
}
float1.c
喜び勇んで上記のような確認用のプログラムの作成してコンパイルし、Z80-COREで実行してみました。
あれ?コンパイルはできたのに<NO FLOAT>って何?って感じです。
確認してみると、printf()関数の書式指定に%fの処理が組み込まれていないことがわかりました。
なんと大胆な。計算できても表示できないんじゃ、計算できているかどうかもわかりませんよね。
本当に計算できているの?
そこで、計算が本当に正しく行われているのか、計算結果を1000倍して整数にキャストして表示するプログラムに変更して動作確認をしてみました。
今度はメイン関数だけを提示。
void main()
{
int i ;
float x = 0.123 ;
for (i = 0; i < 10; i++) {
printf("i = %d, %d\n", i, (int)(x*i*1000)) ;
}
wexit() ; // プログラムの終了
}
float2.c
整数に変換された結果なので、今度は表示されています。
また、計算結果も問題ないようです。(ワンパターンないい加減な計算だけど)
計算結果の表示ができないけれど、実数計算ができることが確認できました。
動作確認したのは掛け算だけなので、四則演算の確認をしておきましょう。
void main()
{
int i ;
float x = 0.123 ;
for (i = 0; i < 10; i++) {
printf("i = %d, %d, %d, %d, %d\n",
i, (int)(x*i*1000), (int)(x/i*1000),
(int)(x+i*1000), (int)(x-i*1000)) ;
}
wexit() ; // プログラムの終了
}
float3.c
ちゃんと動作しているようですが、加減算に関しては、まったく不完全な確認例でしたね。すみません。
実数計算プログラムのコードサイズ
float3.cは評価用の簡単なプログラムですが、コンパイルコードは7Kバイト程度のコードサイズになっています。8K BASICのコード容量に迫る勢いです。
float3.cのコンパイルで作成されたMAPファイルの内容を確認して見ましょう。
_CODEという名前のエリア(セグメント)を取り上げてみます。
表の左端のValueの欄は、その右の関数が配置されているアドレスです。
このアドレスの値と次の行の値との差がその関数のコードサイズを示しています。最大の関数は__print_formatで、2.5K程度を占有していることがわかります。__printf_formatは、printfの表示形式の処理を行う関数ですので、printf関数を使用しようとすると、__printf_formatを含めて、それだけで3Kバイト程度のコード領域を占めてしまうことがわかります。現在は組み込まれていない%fへの対応コードを追加すると、さらにコード量は増大します。なんにせよ、何気なくprintfを使うと、それだけで、TinyBasicが十分動くメモリを消費してしまうということですね。
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
_CODE 00004020 00000F4A = 3914. bytes (REL,CON)
Value Global Global Defined In Module
----- -------------------------------- ------------------------
00004020 _putchar float3
0000403C _main float3
00004140 _exit crt0
00004146 ___sdcc_call_hl
0000414D _vprintf vprintf
00004159 _printf vprintf
00004417 ___mulsint2slong u_16_16_mul
00004445 ___muluint2ulong u_16_16_mul
0000453A __print_format printf_large
00004F5E _strlen
つぎに、_HOMEという名前のエリア(セグメント)を取り上げてみます。
ここには、実数演算で使用する関数群が配置されています。四則演算処理が、それぞれ_fsxxxという関数名で実現されているように見えます。関数名の中に2があるのはtoの短縮形で、それぞれ、データの型変換用の関数の様です。これらの合計バイト数は2775バイトと表示されています。
これを見ると、実数演算を行うプログラムには、その処理用の関数群として、まずは3Kバイト程度が追加されると考える必要があります。
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
_HOME 00004F6E 00000AD7 = 2775. bytes (REL,CON)
Value Global Global Defined In Module
----- -------------------------------- ------------------------
00004F6E ___fssub _fssub
00004F96 ___fsmul _fsmul
00005253 ___fsadd _fsadd
0000567C ___sint2fs _sint2fs
00005684 ___fs2sint _fs2sint
000056B8 ___fsdiv _fsdiv
00005767 ___fs2slong _fs2slong
0000579C ___slong2fs _slong2fs
000057BB ___ulong2fs _ulong2fs
00005866 ___fs2ulong _fs2ulong
00005947 ___fslt _fslt
計算結果の表示を行わない実数計算プリケーション
ちょっと困った状態ではありますが、マンデルブロ集合表示プログラムは、実数計算はするけれども、その計算結果の数値を直接表示しないので、現状のSDCCの応用先にぴったりです。
ということで、別の記事にあらためて、SDCCによるマンデルブロ集合表示プログラムの実行に関するレポートを報告します。