Skip to content

Instantly share code, notes, and snippets.

@komasaru
Created December 15, 2017 02:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save komasaru/3106d62f54ebf16308d08812ec538db3 to your computer and use it in GitHub Desktop.
Save komasaru/3106d62f54ebf16308d08812ec538db3 to your computer and use it in GitHub Desktop.
C++ source code to compute big-digit floats.
/*********************************************
* 浮動小数点数加減算
*********************************************/
#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