質問
私を学習しようとしているCていくことは不可能な作業も大きな数字(つまり、100桁、1000桁ます。それは存在する図書館はこのためには、自分が誰かの助けになっていを実施する試みでやっている。
私が知りたい場合は誰にでもはや提供できる非常に細かいので、dumbed下の説明を任意精度の算術演算.
解決
すべての適切な保存とアルゴリズム処理番号などの小さな部品です。あなたは持っているコンパイラる int
で0-99び出すためのものではありませんの取扱数up to999999まな正の数がここにそれがシンプルに保つために).
いることにより各号三 int
sと同じ規則を使用す(すべて)学んだ後小学校のためには、加算、減算、その他の基本操作.
任意の精度は、図書室、ある定数の制限ベースの種類を表すのに使用される当社の番号でもメモリーできます。
ほか、例えば: 123456 + 78
:
12 34 56
78
-- -- --
12 35 34
かにする必要がありま末
- 初め=0になります。
- 56 + 78 + 0 運=134=34 1を
- 34 + 00 + 1 運=35=35 0を
- 12 + 00 + 0 運=12=12 0を
これは、実際には、どのようほか、一般的にはビットレベルの中にCPUを搭載しています。
控除を受けることができ類似を用控除ベースのタイプしたり、借りたりではなく、増殖できる繰り返し追加(非常に遅い)またはクロス製品(高速化)および部門ではtrickierができず、足し算や引き算の数の関係の部門にいたったん.
私は、実際に書き込まれる図書館はこのようなものを最大限にと権限の可能な場合整数の場合角のを避けるためにオーバーフローが乗二 int
sと一緒に暮らすための16ビット int
に限定されるものでは0-99を9,801(<32,768)の場合角、または32ビット int
用0-9,999を99,980,001(<最大2147483648画素)を大幅に緩和のアルゴリズム
あさらにお得な価格で要注意です。
1/を追加する場合にはを乗じた数を最大スペースを削減して後だあんまりです。例えば、二100-"桁数(桁は int
番号を与えることは決してない以101桁を表します。増殖における12桁の数字による3桁の数字だけでは生み出せない以上15桁数(桁数).
2/加速度normalise(低減の保存に必要なの数が絶対に必要なマイライブラリであったことは別の話なので、ユーザーの決定ができるようにすると速や保管する。
3/かは、正と負の数を減算し、算負の数と同一の追加に相当します。保存できるといったコードを加減し方法電話互調整後。
4/回避を差し引いた大きな数字から小さなものまねで終わう:
10
11-
-- -- -- --
99 99 99 99 (and you still have a borrow).
代わりに、減算10から11日に、それを否定す:
11
10-
--
1 (then negate to get -1).
こちらのコメントがテキストからの図書館かなければいけなかったことです。このコード自体が、残念ながら、著作権がることができるのを取り出すに十分な情報の取扱いの基本的な業務です。えて以下のように -a
や -b
は負の数と a
や b
ゼロまたは正の数が多い。
のための 加, ばありがたいのは、使用の差分を否定:
-a + b becomes b - a
a + -b becomes a - b
のための 減算, ばありがたいのは、使用を否定:
a - -b becomes a + b
-a - b becomes -(a + b)
また特殊な取扱いの確保のたちを差し引いた少人数から大:
small - big becomes -(big - small)
増殖 使用エレベルの数学として
475(a) x 32(b) = 475 x (30 + 2)
= 475 x 30 + 475 x 2
= 4750 x 3 + 475 x 2
= 4750 + 4750 + 4750 + 475 + 475
この実現を抽出しそれぞれの桁32時間がない(下位)を用いての追加を計算する値に追加する結果当初はゼロ).
ShiftLeft
や ShiftRight
業務用いて早く増殖や分割、 LongInt
よりはアピスコーポレーション値(10用数学).上記の例を追加しました475ゼロに2回では最小桁を内蔵の32のになりましたが、950(result=0+950=950).
その左シフト475を4750右シフト32得3.追加4750ゼロに3時14250を加えた結果、950車15200系あおぞらii.
左シフト4750に47500、右シフト3に0になります。から右に移32がゼロにまだ完成して実際に475x32は同15200系あおぞらii.
事業部 もトリッキーで早めの算術のgazinta"方法"が").次長部門 12345 / 27
:
457
+-------
27 | 12345 27 is larger than 1 or 12 so we first use 123.
108 27 goes into 123 4 times, 4 x 27 = 108, 123 - 108 = 15.
---
154 Bring down 4.
135 27 goes into 154 5 times, 5 x 27 = 135, 154 - 135 = 19.
---
195 Bring down 5.
189 27 goes into 195 7 times, 7 x 27 = 189, 195 - 189 = 6.
---
6 Nothing more to bring down, so stop.
そのため 12345 / 27
は 457
と残り 6
.確認:
457 x 27 + 6
= 12339 + 6
= 12345
このメソッドの実装では、より引きの変数(初期ゼロ)となり、セグメントの12345、一つ一つまで以上27になる。
それだけで差し引27日からそのまま下27-数subtractionsのセグメントのトップライン。
なくなった時点でセグメントに参加しました。
だれかの基本アルゴリズムあることができない複雑な演算の場合の数字を大きくなるのである。きみのようなもの GNU複数の高精度の計算書 -で実質的によりよいよ自分が書けます。
では、残念なmisfeatureでそのまま出口までのメモリは致命的な欠陥のための汎用的な図書館"の意)が、できれば見過去のことで良いです。
場合に利用できませんのでライセンスを理由はたくないから申請けに出のための明確な理由)以上、もしくはアルゴリズムが統合のための独自のコードです。
ったもののbodsで MPIR (フォークのGMP)より観光の拠点には最適な立地先課題ケーススタディの潜在的変化-うより開発者向けがたくさん。
他のヒント
車輪を再発明することは、あなた自身の教養と学習にとって非常に良いことですが、それは非常に大きな仕事でもあります。重要な演習であり、自分自身で行った演習であることを思いとどまらせたくはありませんが、大規模なパッケージで対処している作業には微妙で複雑な問題があることに注意してください。
たとえば、乗算。単純に、「男子生徒」メソッドを考えてみてください。つまり、ある数字を別の数字の上に書いてから、学校で学んだように長い掛け算をします。例:
123
x 34
-----
492
+ 3690
---------
4182
ただし、この方法は非常に低速です(O(n ^ 2)、nは桁数です)。代わりに、最新のbignumパッケージは、離散フーリエ変換または数値変換のいずれかを使用して、これを本質的にO(n ln(n))操作に変換します。
そしてこれは整数用です。数値の実数表現(log、sqrt、expなど)でより複雑な関数に入ると、事態はさらに複雑になります。
理論的な背景が必要な場合は、Yapの本の最初の章 <!> quot;アルゴリズム代数の基本的な問題<!> quot; 。すでに述べたように、gmp bignumライブラリは優れたライブラリです。実数については、mpfrを使用して気に入っています。
車輪を再発明しないでください:正方形になるかもしれません!
GNU MP などの試行およびテスト済みのサードパーティライブラリを使用します。
基本的には鉛筆と紙で行うのと同じ方法で行います...
- 数値は、必要に応じて任意のサイズ(
malloc
およびrealloc
を使用することを意味する)を取ることができるバッファー(配列)で表されます - 言語でサポートされている構造を使用して可能な限り基本的な算術演算を実装し、基数ポイントのキャリーと移動を手動で処理します
- 数値解析テキストを精査して、より複雑な関数で処理するための効率的な引数を見つけます
- 必要なだけ実装します。
通常、計算の基本単位として使用します
- 0-99または0-255を含むバイト
- 0-9999または0--65536を含む16ビットワード
- 次を含む32ビットワード...
- ...
アーキテクチャの指示どおり。
2進法または10進法の選択は、スペース効率の最大化、人間の可読性、およびチップでのBinary Coded Decimal(BCD)数学サポートの有無によって異なります。
高等学校レベルの数学でそれを行うことができます。実際には、より高度なアルゴリズムが使用されています。たとえば、2つの1024バイトの数字を追加するには:
unsigned char first[1024], second[1024], result[1025];
unsigned char carry = 0;
unsigned int sum = 0;
for(size_t i = 0; i < 1024; i++)
{
sum = first[i] + second[i] + carry;
carry = sum - 255;
}
結果は、追加の場合に最大値を処理するためにone place
だけ大きくする必要があります。これを見てください:
9
+
9
----
18
TTMath は、学習したい場合に最適なライブラリです。 C ++を使用して構築されています。上記の例は馬鹿げた例ですが、これが加算と減算の一般的な方法です!
このテーマに関する適切なリファレンスは、計算の複雑さの計算です。実装する各操作に必要なスペースがわかります。たとえば、2つのN-digit
番号がある場合、乗算の結果を保存するには2N digits
が必要です。
Mitch が言ったように、それは実装するのが容易ではありません! C ++を知っている場合は、TMTMathをご覧になることをお勧めします。
究極のリファレンス(IMHO)の1つは、KnuthのTAOCP Volume IIです。これらの表現で数値と算術演算を表現するための多くのアルゴリズムについて説明しています。
@Book{Knuth:taocp:2,
author = {Knuth, Donald E.},
title = {The Art of Computer Programming},
volume = {2: Seminumerical Algorithms, second edition},
year = {1981},
publisher = {\Range{Addison}{Wesley}},
isbn = {0-201-03822-6},
}
あなたが自分で大きな整数コードを書きたいと仮定すると、これは驚くほど簡単で、最近やった人として話されます(MATLABで)。ここで私が使ったトリックのいくつかを示します:
-
個々の10進数を二重の数値として保存しました。これにより、多くの操作、特に出力が簡単になります。必要以上に多くのストレージを使用しますが、ここではメモリが安価であり、1組のベクトルを効率的に畳み込むことができる場合、乗算が非常に効率的になります。あるいは、複数の10進数をdoubleに格納できますが、乗算を行うための畳み込みが非常に大きな数値で数値の問題を引き起こす可能性があることに注意してください。
-
符号ビットを個別に保存します。
-
主に2つの数字を追加するには、数字を追加してから、各ステップで桁上げを確認します。
-
少なくともタップで高速の畳み込みコードを持っている場合、数値のペアの乗算は畳み込みとそれに続くキャリーステップとして行うのが最適です。
-
個々の10進数の文字列として数値を格納する場合でも、除算(mod / rem opも)を実行して、結果で一度に約13桁の10進数を取得できます。これは、一度に1桁の10進数のみで機能する除算よりもはるかに効率的です。
-
整数の整数のべき乗を計算するには、指数のバイナリ表現を計算します。次に、必要に応じて繰り返し二乗演算を使用してべき乗を計算します。
-
多くの操作(ファクタリング、素数性テストなど)はpowermod操作の恩恵を受けます。つまり、mod(a ^ p、N)を計算するとき、pがバイナリ形式で表現されているべき乗の各ステップで結果mod Nを減らします。最初にa ^ pを計算しないでください。次に、Nをmodに減らしてください。
これは、PHPで行った単純な(単純な)例です。
<!> quot; Add <!> quot;を実装しました。および<!> quot; Multiply <!> quot;指数の例に使用しました。
http://adevsoft.com/simple-php -arbitrary-precision-integer-big-num-example /
コードスニペット
// Add two big integers
function ba($a, $b)
{
if( $a === "0" ) return $b;
else if( $b === "0") return $a;
$aa = str_split(strrev(strlen($a)>1?ltrim($a,"0"):$a), 9);
$bb = str_split(strrev(strlen($b)>1?ltrim($b,"0"):$b), 9);
$rr = Array();
$maxC = max(Array(count($aa), count($bb)));
$aa = array_pad(array_map("strrev", $aa),$maxC+1,"0");
$bb = array_pad(array_map("strrev", $bb),$maxC+1,"0");
for( $i=0; $i<=$maxC; $i++ )
{
$t = str_pad((string) ($aa[$i] + $bb[$i]), 9, "0", STR_PAD_LEFT);
if( strlen($t) > 9 )
{
$aa[$i+1] = ba($aa[$i+1], substr($t,0,1));
$t = substr($t, 1);
}
array_unshift($rr, $t);
}
return implode($rr);
}