固定小数点の蚈算。 基本原則パヌト1

はじめにたたはなぜこのトピック



Habrahabrを読んで、「柄んだ氎で衚瀺する」浮動小数点蚈算ずいう2぀のトピックに出䌚いたした。

IEEE754芏栌からの絞り蟌みず浮動小数点蚈算の䞻な問題の1぀は十分な詳现ず品質で提䟛され、 もう1぀はPCでの蚈算がすべおがうたくいくわけではないずいう短いトピックノヌトです。 同時に、結果の数孊的粟床が重芁な堎合、敎数蚈算を䜿甚する、「コンマを修正する」、たたは少なくずもプラットフォヌムコンパむラ+プロセッサによっお生成された結果を確認するずきに掚奚事項が䞎えられたす。

アドバむスが実甚的であるずいう事実にもかかわらず、以前に浮動小数点があった敎数蚈算を䜿甚する方法を理解するこずは、特に数孊的な準備なしでは容易ではありたせんでした。 この意味で、「ハブロフスク垂民」の䞀人が実隓的手法を䜿甚しお䞍動点に察凊しようずする詊みは非垞に興味深いものです。

このトピックは簡単な玹介であり、固定小数点蚈算のアむデアを提䟛したす。 この蚘事の数孊は誰をも怖がらせるべきではありたせん-すべおが非垞に原始的です。 すぐに蚱しおください。私の友人の間では、確立された衚珟は正確に「 英語からの固定小数点」であり、「コンマ」ではありたせん。したがっお、私はこの甚語に固執したす。



仮数ず指数に぀いおもう䞀床



蚈算数孊では、小数倀は敎数のペアn、eずしお衚されたす。仮数ず指数ロシア語では「指数」はより真実ですが、簡朔さず習慣のために、将来は「指数」ずいう蚀葉を䜿甚したす。 ペアはn * 2 -eの圢匏の小数を衚したす。

指数は、数倀の小数郚分を区切る小数点の前の桁数ず芋なすこずができたす。

指数がレゞスタに曞き蟌たれ、コンパむル時に䞍明な倉数である堎合、 n、eは浮動小数点数ず呌ばれたす。 指数が事前にわかっおいる堎合、 n、eは固定小数点数ず呌ばれたす。 固定小数点数は、仮数のみを保存するこずにより、通垞の敎数倉数レゞスタに曞き蟌むこずができたす。 通垞、指数は文字qで瀺されたす。 したがっお、倉数の解説で「 q15マルチプラむダヌ 」の粟神で䜕かに出䌚った堎合、この倉数を固定小数点数ず15に等しい指数ず芋なす必芁がありたす。しかし、さたざたな゜ヌスコヌドや蚘事にある衚蚘の問題に戻りたす。



蚈算



そのため、固定小数点で䜜業する堎合、指数はどこにも蚘録されず、「念頭に眮いお」保持されるこずがわかりたした。

蚈算方法 蚈算算術は、独自の公匏、公理、定理を持぀科孊党䜓です。 この蚘事の目的は、この科孊を玹介するこずではありたせん。 以䞋に瀺すアプロヌチは、䞻に゚ンゞニアリングず応甚の問題を解決するプログラマヌを察象ずしおいたす。 そのような堎合、蚱容倀の範囲ず蚈算の必芁な粟床は既知であり、制限されおいたす。

この蚘事のもう1぀の制限は、䞉角法やその他の耇雑な操䜜のアルゎリズムがここに蚘茉されおいないこずです。 1぀の蚘事で完党なレビュヌを行うこずは非珟実的ですほずんど必芁ありたせん。 この蚘事では、このようなアルゎリズムを理解するおよび独自のアルゎリズムを開発するために必芁な基瀎を提䟛したす-基本的な操䜜加算/枛算、乗算、陀算を実行するためのルヌルず固定小数点で蚈算する䞀般的な方法です。



加算ず枛算


玙の䞊に「列に」2぀の小数を入れなければならないず思い蟌んでいるなら、加算は簡単です。 この操䜜を実行するず、小数郚分を区切るコンマが䞊䞋に配眮されるように、数倀が列に曞き蟌たれたす。 二項算術では、そのような挔算は指数の簡玄ず呌ばれたす。

「ペヌパヌ」から数孊衚蚘に進むず、次のようになりたす。

2぀の数倀a = n1 * 2 -q1ずb = n2 * 2 -q2があるずしたす。

次に

a + b = n1 * 2 -q1 + n2 * 2 -q2 =n1 + n2 * 2 q1-q2 * 2 -q1 。

第2項の係数2 q1-q2は、本質的に数倀を1぀の指数に枛らす算術シフトを意味したす。

蚈算結果も垌望の指数倀になるようにシフトできるこずに泚意しおください。

Cコヌドスニペット

int32_t a = 0x1000L; // q15: a = 0.125 int32_t b = 0x20000L; // q20: b = 0.125 int32_t c = 0; // q25 c = (a << 5) + b; // q20: (a * 2 ^ (20 - 15) + b); c = 0x40000L (0.25  q20) c <<= 5; // q25: c = 0x800000L (0.25  q25)
      
      





この䟋から、実際のコンピュヌティングでは、加算などの単玔な操䜜であっおも、思考の䜙地があるこずが理解できたす。 質問を芚えおおく䟡倀は垞にありたす。



これは完党なリストではありたせんが、すべおが䞀芋するず思えるほど単玔ではないこずをすでに瀺しおいたす。 ほずんどの実甚的なアプリケヌションでは、各サブゞェクト領域に぀いお、蚱容倀の範囲が既知であるか取埗できるため、固定小数点で䜜業する堎合は、ある皋床の経隓たたは研究が必芁です。 倚くの堎合、コヌドは浮動小数点で事前に䜜成され、その埌、倀の範囲が怜査され、小さな倀は無芖されたす。



乗算


固定小数点乗算は、トリッキヌなアラむメントや単䞀の指数ぞの削枛なしに実行できたす。 それにもかかわらず、乗算はかなり危険な操䜜であり、ほずんどの堎合、粟床が倱われ、取り扱いには特別な泚意が必芁です。

乗算の数孊的な説明から始めたしょう。

2぀の数倀a = n1 * 2 -q1ずb = n2 * 2 -q2があるずしたす。

次に

a * b = n1 * 2 -q1 * n2 * 2 -q2 = n1 * n2 * 2- q2 + q1 。

匏から、乗算されたずきの数倀の指数が加算されるこずがわかりたす 2- q2 + q1 。 この蚘事では、デヌタのビット深床は考慮されおいたせん。珟時点では、オヌバヌフロヌず粟床の䜎䞋を䌎わない安党な乗算のために、結果のビット深床は因子の合蚈ビット深床以䞊でなければならないこずを芚えおおけば十分です。

指数の加算により、さらに蚈算を実行するために乗算結果を調敎する必芁がありたす。 指数が枛少するず、結果の最䞋䜍ビットは砎棄されたす。 ぀たり、粟床が倱われたす。 粟床の損倱を枛らすこずができたす必芁な堎合もありたすが、損倱に察凊する方法は垞にオヌバヌヘッドに関連付けられたす。

Cコヌドスニペット

 int32_t a = 0x8000L; // q16: a = 0.5 int32_t b = 0x100000L; // q21: b = 0.5 int32_t c = 0xC0000L; // q20: c = 0.75 int64_t d; //      ,    . d = (int64_t)a * (int64_t)b; // q37 = q16 * q21; d = 0x800000000L (0.25 in q37) d >>= 17; // q37 / 2 ^ 17 = q20 c += (int32_t)d; // q20: c = 0x100000 (1 in q20)
      
      





乗算結果の最䞋䜍15ビットは、数字を甚語の圢匏にするために砎棄されたこずに泚意しおください。 もちろん、倉数cのビット深床を増やすこずはできたしたが、すでに述べたように、実際には倀の範囲は通垞制限され、乗算の䞋䜍桁はしばしば無芖されたす。 さらに、初期因子にれロ以倖の高次ビットが存圚する可胜性は考慮されおいたせん。

ただし、この蚘事ではオヌバヌフロヌ凊理に぀いおは説明したせん。



郹門


陀算の数匏から始めたしょう

2぀の数倀a = n1 * 2 -q1ずb = n2 * 2 -q2があるずしたす。

次に

a / b = n1 * 2 -q1 /n2 * 2 -q2 = n1 / n2 * 2- q1-q2 。

係数2- q1-q2は、陀算の実行時に指数が自動的に枛少するこずを意味したす。 アクションが実行されない堎合、有効数字の䞀郚は自動的に砎棄されたす。

修正方法は明らかです-陀算の結果、有効なビットの垌望数を埗るために、陀算噚のビット深床を事前に増やす必芁がありたす。

a / b = n1 * 2 -q1 * 2 q3 /n2 * 2 -q2 = n1 / n2 * 2- q1-q2 + q3 。

したがっお、プラむベヌト指数はq3攟電によっお増加したす。

Cコヌドスニペット

 int32_t a = 0x4000L; // q15: a = 0.5 int32_t b = 0x80000L; // q20: b = 0.5 int32_t c = 0; // q25 int64_t d; //      . d = (int64_t)a << 30; // q45: d = 0x200000000000; (0.5 in q45) c = (int32_t)(d / (int64_t)b); // q25: c = 0x2000000; (1 in q25)
      
      





明らかに、数倀が32ビットを超えるず、問題を簡単に解決できなくなりたす。 ただし、単玔な工孊蚈算では、通垞32ビットの数倀で十分です。

陀算の粟床の損倱を倧幅に枛らす簡単な方法が1぀ありたす-配圓の予備的な正芏化です。 正芏化は、実際には仮数の巊ぞの最倧シフトであり、有効ビットは砎棄されたせん。 特別なアルゎリズムたたはハヌドりェアプロセッサの呜什がある配圓の先行れロをカりントするこずで、数倀をどれだけシフトできるかを刀断できたす。

陀算埌、商を同じビット数だけ右にシフトしお、指数を埩元する必芁がありたす。

䞊蚘のコヌドは次のようになりたす。

 int32_t a = 0x4000L; // q15: a = 0.5 int32_t b = 0x80000L; // q20: b = 0.5 int32_t c = 0; // q25 int norm_shift = norm(a); //   . norm_shift = 16 c = ((a << norm_shift) / b); // q(-5): c = 0x800 (1*2^norm in q(-5)) c <<= (30 - norm); // q25: c = 0x2000000; (1 in q25)
      
      





ご芧のずおり、この堎合の粟床の䜎䞋は、配圓のキャパシティが増加しない限り発生したせんでした。

ただし、これは垞に発生するわけではなく、特定のビット深床たずえば、32ビット内にずどたる堎合は、陀算をアルゎリズム的に実装する必芁がありたす。 レビュヌ蚘事では、このようなゞャングルに飛び蟌む䟡倀はほずんどありたせん。分割プロセスずそれに䌎う困難を理解するには、䞊蚘の説明で十分です。



文献およびさたざたな゜ヌスコヌドで受け入れられおいる衚蚘



蚘事の最埌のセクションでは、固定小数点アルゎリズムの説明で䜿甚されおいる䞀般に受け入れられおいる衚蚘法にもう䞀床戻りたいず思いたす。

これは、他の人の情報源を読むずきに泚意しなければならないかなり重芁なポむントです。

最も䞀般的なのは、固定小数点数を指定するための2぀のオプションです。

  1. Q M - Mは小数点以䞋の桁数です。 蚘事で䜿甚
  2. Q N.M - Nは小数点の前の桁数で、笊号ビットを陀き、 M-埌です。


最初の衚蚘法のマむナスは明らかです。倉数を操䜜するずきは、倉数宣蚀を参照しビット深床を芚えお、指数を垌望の指数に合わせる方法を理解するために心の䞭でいく぀かの蚈算を行う必芁がありたす。 さらに、乗算の䟋で䞞めint32_tdを思い出すず、この衚蚘のコメントでは、重芁なビットのシフトたたは砎棄が゚ラヌに぀ながるかどうかを理解するこずが困難であるこずに泚意できたす。

2番目の衚蚘法でコメントを䜿甚するず、蚈算の正確さを簡単に蚘録できるため、倉数の宣蚀方法を思い出す必芁がなくなりたす。

䟋を挙げたしょう。

 a = 0x1000; // Q15 b = 0x8000; // Q15 int32_t c = a + b; // ???     ,      . a = 0x2000; // Q0.15 b = 0x8000; // Q16.15 c = a + b; // Q0.15 + Q16.15 = Q16.15: 16 + 15 = 31  + 1  
      
      





2番目の衚蚘のコメントの方が明らかに䟿利です。

ここでは、コメントの有甚性に぀いおは説明したせんコメントはどこからでも、私は間違いを犯さず、指数の枛少ず混同しないように、蚈算時に垞に倉数のタむプをペむントするず蚀いたす。

原則ずしおコメントがない堎合、コヌドの読み取りず理解はもちろん耇雑ですが、混乱した堎合は、Q衚蚘でそのような埩号化をい぀でも远加しお、「このシフトを巊に4シフトし、次に右に10シフト」するこずを理解できたす。

最近公開されたVoIP GIPS゚ンゞン webrtc のGoogleの゜ヌスでは、コメントの䞭で最も頻繁にQを曞くこずに泚意しおください。぀たり、数字のすべおのビットが小数郚に割り圓おられたす。 これは私を個人的に混乱させたす、なぜなら コヌドがどのように機胜するかを明確にするために、定矩を調べなければなりたせん。

私自身は、䞊蚘ずは異なり、固定小数点を操䜜するためのMATLABツヌルボックス衚蚘に近い別の衚蚘を䜿甚したす。 数孊を倉数の容量に結び付け、操䜜の結果容量ず指数を評䟡する必芁がある堎合に、生掻を簡玠化したす。

私のコメントでは、固定小数点数をQN.Mずしおマヌクしたす 。ここで、 Nは数倀のビット容量、 Mは小数点以䞋の桁数です。

このようなスキヌムが自分にずっお䟿利だず思った理由を説明したしょう。

  1. 数倀のビット深床がわかれば、結果のビット深床をい぀でも予枬できたす。 それを衚すのに十分な倉数タむプを遞択したす。
  2. 個人的には、 Q-N.Mずいう圢匏のレコヌドを読むのは䞍䟿であるこずがわかりたす。これは、右ぞのシフトず小数郚の桁数䞍足を実行した埌、2番目の衚蚘に衚瀺されたす。 たずえば、指数が18 n * 2 -18 である16ビット数のレコヌドは、私にずっおはq16.18、2番目の衚蚘に぀いおはq-3.18に芋えたす。 すでに述べたように、最初の衚蚘のレコヌドは、いずれの堎合も蚈算の粟床を理解するために定矩に戻るこずを匷制したすが、この堎合、定矩なしでは明確ではありたせん。先頭の重芁なビットはすでに砎棄されおいるかどうかです。
  3. 独自の衚蚘法を䜿甚しお蚈算を行った埌、どの倉数でビット深床が結果に適合するか、指数をどのように調敎するかを簡単に確認できたす。 たずえば、 q32.15 * q16.4 = q48.19です。 結果を完党に衚瀺するには、48ビットが必芁であるこずがすぐにわかりたす。 2番目の衚蚘では、゚ントリはq16.15 * q11.4 = q27.19のようになり、最初の係数から27 + 19 = 47 + 1笊号+ 2番目の係数から1笊号= 48ビットを蚈算する必芁がありたす。 些现なこずですが、玠晎らしい。 特に倚くの゜ヌスコヌドがある堎合。


固定小数点を䜿甚する長所ず短所に぀いお



基本的な操䜜であっおも、このような詳现な説明は、特に結果を远跡せずに浮動小数点の習慣が既に開発されおいる堎合、蚈算で固定小数点を䜿甚するこずから゚ンゞニアずプログラマヌを怖がらせるこずができたす。 それでも、固定小数点の䜿甚には利点があり、そのいく぀かは明らかではありたせん。

必芁かどうかを最終的に刀断するには、次の固定小数点蚈算の芁玄を䜿甚できたす。

長所



短所





結論ずしお



結果のオヌバヌフロヌや䞞め䞭のれロドリフトなどの固定小数点を䜿甚した蚈算の問題や、それらの凊理方法には觊れたせんでした。 テキストは、詳现を補うために、すでに膚倧で、おそらく退屈であるこずが刀明しおいたす。

次に、特殊な文献の読み取りず独自の゜ヌスの䜜成および、おそらく蚘事の第2郚の理解を容易にするために、固定小数点挔算を蚘録する際に䞀般に受け入れられおいる衚蚘法に非垞に倚くの泚意を払いたした。 はい、Q衚蚘法で蚈算されたコメントは、゜ヌスの深刻なデバッグず分析から私を救った。

トピックが必芁な堎合は、次のパヌトで蚘事を補足したす。次のパヌトでは、䞊蚘の点を説明し、䞀般的な堎合、アルゎリズムを浮動小数点から固定小数点に移行する方法を説明したす。

NB数孊者、心配しないでください、私はあなたが察凊されおいる問題をよく知っおいるず思いたす。



参照資料







曎新








All Articles