Created
December 15, 2017 02:38
-
-
Save komasaru/3106d62f54ebf16308d08812ec538db3 to your computer and use it in GitHub Desktop.
C++ source code to compute big-digit floats.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********************************************* | |
* 浮動小数点数加減算 | |
*********************************************/ | |
#include <cstdlib> // for rand() | |
#include <iostream> // for cout | |
#include <math.h> // for pow() | |
#include <stdio.h> // for printf() | |
#include <time.h> // for time() | |
#define D_MAX 11 // 有効桁数(小数点以下+べき指数) | |
using namespace std; | |
/* | |
* 計算クラス | |
*/ | |
class Calc | |
{ | |
int A[D_MAX]; // 被加減数配列 | |
int B[D_MAX]; // 加数配列 | |
int C[D_MAX]; // 減数配列 | |
public: | |
Calc(); // コンストラクタ | |
void calc(); // 計算 | |
private: | |
void add(int *, int *, int *, int, int); // 加減算 ( 固定長整数 ) | |
void fadd(int *, int *, int *, int, int); // 加減算 ( 浮動小数点数 ) | |
void setv(int, int*, int); // 値セット ( 全配列に同じ整数をセット ) | |
void copy(int *, int*, int); // 値コピー ( 全配列をそのままコピー ) | |
void norm(int *, int); // 正規化 ( 固定長整数 ) | |
void fnorm(int *, int); // 正規化 ( 浮動小数点数 ) | |
void fdisp(int *, int); // 結果出力 ( 指数表示 ) | |
}; | |
/* | |
* コンストラクタ | |
*/ | |
Calc::Calc() | |
{ | |
// 使用する被加減数・加減数を設定(テストなので適当な乱数を使用) | |
// ( A + B, A - C で A > C となることが条件だが | |
// 稀に条件に合致しない値が生成されるかもしれない ) | |
srand((unsigned int)time(NULL)); // 乱数の種を初期化 | |
A[0] = rand() % (D_MAX - 1) + 1; // Aのべき指数部 | |
B[0] = rand() % (D_MAX - 1) + 1; // Bのべき指数部 | |
C[0] = A[0] - rand() % A[0] - 1; // Cのべき指数部 | |
for (int i = 1; i < D_MAX; i++) A[i] = rand() % 10; // Aの小数部 | |
for (int i = 1; i < D_MAX; i++) B[i] = rand() % 10; // Bの小数部 | |
for (int i = 1; i < D_MAX; i++) C[i] = rand() % 10; // Bの小数部 | |
} | |
/* | |
* 計算 | |
*/ | |
void Calc::calc() | |
{ | |
// 各種宣言 | |
int size = D_MAX; // 配列サイズ | |
int a[size]; // 被加減数配列 | |
int b[size]; // 加数配列 | |
int c[size]; // 減数配列 | |
int z[size + 1]; // 計算結果配列 | |
// 初期設定 | |
copy(A, a, size); // 被加減数配列 | |
copy(B, b, size); // 加数配列 | |
copy(C, c, size); // 減数配列 | |
// 計算する被加減数・加数・減数を出力 | |
printf("A =\n"); fdisp(a, size); | |
printf("B =\n"); fdisp(b, size); | |
printf("C =\n"); fdisp(c, size); | |
// 加算 ( Z = A + B ) | |
fadd(a, b, z, size, 1); | |
// 結果出力 | |
printf("A + B =\n"); fdisp(z, size); | |
// 減算 ( Z = A - C ) | |
fadd(a, c, z, size, -1); | |
// 結果出力 | |
printf("A - C =\n"); fdisp(z, size); | |
} | |
/* | |
* 加減算 | |
* ( 固定長整数同士の加減算, 正規化含む ) | |
* | |
* a [I ] 被加減数配列 | |
* b [I ] 加減数配列 | |
* size [I ] 配列数(A, B) | |
* z [ O] 出力データ配列(Z = A + B or Z = A - B) | |
* id [I ] 1: 加算(A + B(, -1: 減算(A - B) | |
*/ | |
void Calc::add(int *a, int *b, int *z, int size, int id) | |
{ | |
int i; // LOOPインデックス | |
// 計算 | |
if (id >= 0) { // 加算 | |
for (i = 0; i < size; i++) | |
z[i] = a[i] + b[i]; | |
} else { // 減算 | |
for (i = 0; i < size; i++) | |
z[i] = a[i] - b[i]; | |
} | |
// 正規化 | |
norm(z, size); | |
} | |
/* | |
* 加減算 | |
* ( 浮動小数点数同士の加減算, 正規化含む ) | |
* | |
* a [I ] 被加減数配列 | |
* b [I ] 加減数配列 | |
* size [I ] 配列数(A, B) | |
* z [ O] 出力データ配列(Z = A + B or Z = A - B) | |
* id [I ] 1: 加算(A + B), -1: 減算(A - B) | |
*/ | |
void Calc::fadd(int *a, int *b, int *z, int size, int id) | |
{ | |
int k; // べき指数の差 | |
int i; // LOOPインデックス | |
// 計算 | |
if (a[0] >= b[0]) { // A のべき指数 >= B のべき指数 | |
k = a[0] - b[0]; | |
copy(a, z, k + 1); | |
add(&a[k + 1], &b[1], &z[k + 1], size - k - 1, id); | |
} else { // A のべき指数 < B のべき指数 | |
z[0] = b[0]; | |
k = b[0] - a[0]; | |
// 位の異なる部分 | |
if (id >= 0) { // 加算 | |
copy(&b[1], &z[1], k); | |
} else { // 減算 | |
for (i = 1; i <= k; i++) z[i] = -b[i]; | |
} | |
// 位の同じ部分の加減算 | |
add(&a[1], &b[k + 1], &z[k + 1], size - k - 1, id); | |
} | |
// 正規化 | |
norm(&z[1], size - 1); // 固定長整数 | |
fnorm(z, size); // 浮動小数点数 | |
} | |
/* | |
* 値セット | |
* ( 全配列に同じ整数をセット ) | |
* | |
* v [I ] セットする整数 | |
* z [ O] セット先配列 | |
* size [I ] 配列サイズ | |
*/ | |
void Calc::setv(int v, int *z, int size) { | |
int i; // LOOPインデックス | |
for (i = 0; i < size; i++) z[i] = v; | |
} | |
/* | |
* 値コピー | |
* ( 全配列をコピー ) | |
* | |
* a [I ] コピー元配列 | |
* z [ O] コピー先配列 | |
* size [I ] 配列サイズ | |
*/ | |
void Calc::copy(int *a, int *z, int size) { | |
int i; // LOOPインデックス | |
for (i = 0; i < size; i++) | |
z[i] = a[i]; | |
} | |
/* | |
* 正規化 | |
* ( Fixed Normalize(A) by Base-Value ) | |
* | |
* a [IO] 正規化前データ・正規化後データ配列 | |
* size [I ] 配列数 | |
*/ | |
void Calc::norm(int *a, int size) { | |
int i; // LOOPインデックス | |
int cr = 0; // 繰り上がり | |
for (i = size - 1; i >= 1; i--) { | |
cr = (int)(a[i] / 10); | |
a[i] -= cr * 10; | |
a[i - 1] += cr; | |
} | |
for (i = size - 1; i >= 1; i--) { | |
if (a[i] < 0) { | |
a[i-1] -= 1; | |
a[i] += 10; | |
} | |
} | |
} | |
/* | |
* 正規化 | |
* ( Floating Normalize(A) ) | |
* | |
* a [IO] 正規化前データ・正規化後データ配列 | |
* size [I ] 配列数 | |
*/ | |
void Calc::fnorm(int *a, int size) { | |
int exp; // Exponent | |
int i; // LOOPインデックス | |
int k; // 上位の 0 の個数 | |
// 小数点以下第1位が桁あふれする場合、右に1桁シフト&べき指数加算 | |
if (a[1] >= 10) { | |
for (i = size - 2; i >= 2; i--) a[i + 1] = a[i]; | |
a[2] = a[1] % 10; | |
a[1] = a[1] / 10; | |
a[0]++; | |
} | |
// 正規化前のべき指数を退避 | |
exp = a[0]; | |
// 上位の 0 の個数をカウント | |
for (i = 1; i <= size; i++) if (a[i] != 0) break; | |
k = i - 1; | |
// 上位の 0 の部分に以降の数字をシフト | |
for (i = 1; i <= size - k; i++) a[i] = a[i + k]; | |
// シフト後の下位に 0 をセット | |
setv(0, &a[size - k], k); | |
// べき指数セット | |
a[0] = exp - k; | |
} | |
/* | |
* 結果出力 (指数表示) | |
* | |
* s [I ] 結果出力データ配列 | |
* size [I ] 配列数 | |
*/ | |
void Calc::fdisp(int *s, int size) | |
{ | |
int i; | |
printf("0."); | |
// 1行に50桁出力 | |
for (i = 1; i < size; i++) { | |
printf("%d", s[i]); | |
if (i % 10 == 0 && i != 0) printf(" "); | |
if (i % 50 == 0 && i != 0) printf("\n "); | |
} | |
// べき指数 | |
if (s[0] < 0) { | |
printf(" * 10^(%d)\n", s[0]); | |
} else { | |
printf(" * 10^%d\n", s[0]); | |
} | |
printf("\n"); | |
} | |
/* | |
* メイン処理 | |
*/ | |
int main() | |
{ | |
try | |
{ | |
// 計算クラスインスタンス化 | |
Calc objCalc; | |
// 計算 | |
objCalc.calc(); | |
} | |
catch (...) { | |
cout << "例外発生!" << endl; | |
return -1; | |
} | |
// 正常終了 | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment