私はもともとPower PCアーキテクチャーで実行され、gnu 3.0.6でコンパイルされた古いCモジュールを使用しています
IntelハードウェアのVS2012プロジェクトで実行するように移植しています。
モジュールは、ビットマップファイルと他のIOに基づいて嵐の雲の3Dモデルを作成します。
符号付きの大きさ(x座標とy座標、-differentials)が1024 * 1024で乗算されるのを見続けていますが、その理由はわかりません。これらの量は、signed intに格納されます。
これらの数量の1つがモジュールから出力されるときはいつでも、20だけ右シフトされ、1024 * 1024による乗算がキャンセルされるようです。
誰かがここで何が起こっているのか知っていますか?
ありがとう
編集:1つのケースは、256x256グリッドに埋め込まれたラインのx微分とy微分を使用して、ライン全体を反復する場合です。ここに、ある角度シータとグリッド内の特定の開始点(x、y)によって定義された光線があります。始点座標も1024×1024の商品です
#define KINT 1024*1024
float x_disp, y_disp;
int x, y, dx, dy;
//initializing code
x = (int)(KINT*x_disp);
y = (int)(KINT*y_disp);
//as theta ranges across [-pi/2, pi/2], itheta ranges over [0, 720]
dx = (int)(KINT*sin_table[itheta]);
dy = (int)(KINT*cos_table[itheta]);
考えてみれば、sin_table(itheta)の前に(-1)がない理由がわかりません。
256x256グリッド内に埋め込まれた線は、次のように座標を計算することによってトラバースされます。
for (int i = 0; i < 256; i++)
{
int posx = (x>>20);
int posy = (y>>20);
if((posx|posy)&0xffffff00 == 0)
{
char val = grid[x][y];
//do something with val
}
x += dx;
y += dy;
}
コードを確認せずに(まったく)確認することは困難ですが、小数点の前に12ビット、後の20ビットで固定小数点演算を実装しているように聞こえます。
これらのうち2つを掛け合わせる場合は、右シフトを実行して結果を正しい表現に戻す必要があります。つまり、各入力は合計32ビットであるため、これらを乗算すると、結果は明らかに64ビットになり、その32ビットを保持する必要があります。ただし、正しい 32ビットを維持する必要があります。入力で小数部の20ビットと仮数部の12ビットから始めたので、結果では小数部の40ビットと仮数部の24ビットが得られます。したがって、20だけ右シフトし、下位32ビットを保持して12:20のフォーマットされた結果を取得します(そして、結果の上位ビットはゼロであるか、結果が表すものをオーバーフローしただけです)。
多くの人は10進数で考える方が簡単だと思います。それでは、(たとえば)-999.999〜+999.999を処理できるが、整数として格納および操作できる10進表記について考えてみましょう。
したがって、数値を格納するには、まず1000を掛けるので、123.456がある場合(たとえば)123'456になります。さて、このように数字を追加すれば、特別なことをする必要はありません。したがって、123'456から234'567を加算すると、358'023が返されます。これは358.023を表します(これが正しい答えです)。
しかし、これらの数値のうち2つを掛け合わせると、結果は望んだものとは異なります。たとえば、2.2 x 2.3を考えてみましょう。私たちのフォーマットでは、2'200 x 2'300になります。これらを乗算すると、5'060'000が得られ、5'060.000に変換されます。結果は1'000倍高すぎます(これを値に適用して表記に入れるのと同じ係数)。したがって、乗算後に正しい答えを得るには、小数点以下3桁右にシフトする必要があるため、5.06に変換される5'060になります。
あなたが見ているコードはほとんど同じことをしているように聞こえますが、ナイスで10進数の乗数を使用する代わりに、ナイスで2進数の乗数を使用しています。これにより、単純に右シフトを実行することで、乗算後の結果をバイナリコンピューターで簡単に "修正"できます(一方、10の累乗で除算すると、比較的遅くなります)。
さらに一歩先を見ます:なぜ彼らはこれをするのですか? 2つの明らかな可能性を見ることができます。最初で最も明白なのは、速度です。特に多くの古いプロセッサでは、整数演算が浮動小数点演算よりも大幅に高速であることがかなり一般的でした。
2番目の可能性は予測可能性です。固定小数点では、基本的に整数演算を行います。整数演算はかなり単純で理解しやすいです。対照的に、代わりに浮動小数点演算を使用すると、多くの人が少し不思議に思う領域に入ります。人々は最初、浮動小数点は数学の実数のようであると考える傾向がありますが、2つは実際には同じではなく、その違いを理解するのは難しく、初心者にとってはしばしば難しい場合があります。予測する領域で。固定小数点(スケーリングされた整数)を使用することで、予測不可能で理解しにくいものを簡単に回避できます。
このシフトが一方向に行われ、その後逆に行われるという事実は、これがおそらくこれらの値で追加の帯域幅を使用するためのハックであることを示唆しています。つまり、下位20ビットは他の情報を保持するために使用されています。これが私の推測です。
もう1つのオプションは、これが上位ビットをクリアする間抜けな方法であることです。これはありそうにないように見えますが、特に アーキテクチャーから別のアーキテクチャー に移動するときに、これが発生する可能性があるのではないかと心配しています。
確実にコードをトレースしますが、新しいアーキテクチャのintサイズが少なくとも古いものと同じであることを確実に確認する必要があります。
シフトのもう一つの理由-
一部のデータシステムでは、従来の右揃えではなく、フィールド内のデータを左揃えにします。たとえば、10ビットのアナログ-デジタルコンバーターは、通常、16ビットフィールドの10ビットの読み取り値を左揃えまたは右揃えにするオプションを提供します。この機能は、一部のArduinoデバイスで使用されるAtmega32u4チップに存在します- datasheet 313ページを参照してください。ADMUXレジスタのADLARビット。
左揃えデータは、小数部が常にゼロである場合、上記の Jerry Coffin で説明されているシステムと基本的に同じです。
これらの種類の固定小数点システムの背後にある大きな推進力の1つは、プロセッサに浮動小数点ユニットがなく、小数点の後に必要な精度の桁数が事前にわかっている場合です。 2 ^ 10はおよそ10 ^ 3なので、10ビット左シフトするごとに、小数点がおよそ3桁右に移動します。 X.yyy形式の数値に対して整数演算を行うことができ、結果を表示するときは、10進数に変換した後、適切な場所に小数点を挿入するだけです。