質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.63%

C言語:自分で変数を作る。

解決済

回答 6

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,992

strike1217

score 579

この質問に至った経緯から説明します。

√3を小数計算をするプログラムを作りました。

double x = 1;

for (int i = 1; i <= N; i++) {
    x = ((x*x + a) / (2 * x));
        printf("%d : %02.100lf\n", i, x);
    }


省略していますが、√3 なので、a = 3になっています。
ニュートン法を使って漸化式を作りました。

結果は以下のようになりました。

calc root : 3
1 : 2.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000
2 : 1.75000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000
3 : 1.73214285714285720629845855000894516706466674804687500000000000000000000000000000000000000
00000000000
4 : 1.73205081001472738222446423606015741825103759765625000000000000000000000000000000000000000
00000000000
5 : 1.73205080756887719317660412343684583902359008789062500000000000000000000000000000000000000
00000000000
6 : 1.73205080756887741522120904846815392374992370605468750000000000000000000000000000000000000
00000000000
7 : 1.73205080756887719317660412343684583902359008789062500000000000000000000000000000000000000
00000000000
8 : 1.73205080756887741522120904846815392374992370605468750000000000000000000000000000000000000
00000000000
9 : 1.73205080756887719317660412343684583902359008789062500000000000000000000000000000000000000
00000000000
10 : 1.7320508075688774152212090484681539237499237060546875000000000000000000000000000000000000
000000000000
11 : 1.7320508075688771931766041234368458390235900878906250000000000000000000000000000000000000
000000000000
12 : 1.7320508075688774152212090484681539237499237060546875000000000000000000000000000000000000
000000000000
13 : 1.7320508075688771931766041234368458390235900878906250000000000000000000000000000000000000
000000000000
・・・

結果が繰り返されているので、
「doubleの型に収まる桁の限界がきているのかな??」
と思っているのですが、以下のサイトを見つけました。(わかりやすいです。)
浮動小数点数型と誤差

2.225074 10^-308 < double の絶対値 < 1.797693 10^+308
こうなっていたので、「あれ?? 全然大丈夫そうだけど・・・」
なんで、こんなに小さい桁数で結果が繰り返されているのか不明なのですが・・・

ここでdoubleよりもっと大きい桁を扱える変数を自作する方法を教えて下さい。

以前、以下のような質問をしました。
int型の先頭アドレスについてです。

char型を複数使うことでint型を作り出しているなら、それと同じ原理でオリジナル変数をつくればもっと結果の繰り返しを遅らせることができるのではないかと思っています。

ちなみに、long double を使ってみましたが、結果は同じでした。

ちょっと説明しにくいのですが、
より大きな桁を扱うための変数の作り方を教えてほしいです。
お願いします。

環境は windows 64bit, 64bitコンパイルをしました。

[追記]

Chironianさんの回答を元に面白いサイトを発見しましたので、載せておきますね。
多倍長演算

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 6

checkベストアンサー

+4

こんにちは。

リンク先にも書かれている通り下記のような処理系が多いです。

double 型の精度(有効桁数)は2進数にして 53 (=52+1) 桁であり,10進数では約 15 桁となる.

10進数15桁が有効桁数です。

1.7320508075688774152212090484681539237499237060546875
1.7320508075688771931766041234368458390235900878906250

の一致している桁数は16桁ですので、ほぼ合ってます。
多くの処理系は、IEEE 754に準拠してますので、15.95桁が有効桁数ですから、妥当な結果と思います。

ちなみに、long double を使ってみましたが、結果は同じでした。

Visual C++はlong doubleとdoubleは同じ倍精度(binary64)だったと思います。
MinGW(gcc)なら、long doubleは拡張精度形式(80ビット使います)なのでもう少し精度が上がると思います。

char型を複数使うことでint型を作り出しているなら、それと同じ原理でオリジナル変数をつくればもっと結果の繰り返しを遅らせることができるのではないかと思っています。

それをやっているのはハードウェア(CPU)です。
なので、CPUが回路的に実装していないサイズを使うのは容易ではありません。

とは言え、ソフトウェアで拡張することは可能ですね。
C言語は型を拡張する仕組みを持っていないので、型を自力で作ることはできないです。

C++には型を拡張するclassがあるので可能です。でも、かなりたいへんと思います。
任意精度で実数演算を行うライブラリを探した方が速いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/03 18:31

    仮数部だけなら整数だけですよ。
    指数部も含めて10進数へ変換されているから小数点以下がある形式で出力されてます。

    キャンセル

  • 2017/03/03 18:47

    あ!
    そういうことですか!
    分かりました。

    キャンセル

  • 2017/03/03 20:45 編集

    演算子のオーバーロードで実現できることがわかったので、ベストアンサーにさせてもらいますね。
    double型のフォーマットについては再度質問するかもしれません。

    キャンセル

+2

C言語のdoubleは多くの場合、浮動小数点数になっています。大きい数字を「2.3×10^27」のように書くことがありますが、そんな感じで、「1.11011×2^15」のような形で記録されています。そのため、精度の絶対的な大きさは値の大きさによって変化します(10進法で16桁程度)。

一般によく使われるIEEE 754の倍精度64ビットの場合、

  • 符号…1ビット
  • 仮数部…52ビット
  • 指数部…11ビット

というように配分されています。

このような複雑な構造なので、さらに大きな数を自分で作ろうとしても、正しい演算ルーチンを作るだけで一苦労です。GMPなど、既存の演算ルーチンを使うのが手っ取り早いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/02 19:00

    「精度の絶対的な大きさは値の大きさによって変化します」
    そうなんですか!

    キャンセル

  • 2017/03/02 19:03

    GMPについて調べてみますね。

    キャンセル

+2

小さい桁数で値が繰り返されるのはこの漸化式では自然なことだと思います。
無限に繰り返すことで平方根の正確な値に限りなく近づいていく式、なので、元々無理数の小数部をより小さい方に向かって計算し続ける式なわけで、結果はこれで良いと思います。

有効桁数15以下の値が変わり続けるのはなぜなのか?
それは、有効桁数15桁というのは、15桁までは「妥当な近似値」で表せる、という意味だからです。
1.732050807568877より下の部分、16桁以降の数値は誤差部分なんです。

倍精度少数は元々全ての値を適切に表現できるわけではありません。
このサイトなんかが分かりやすいです。

このため、値が範囲内であっても、倍精度少数が表してる値は全て「近似値」なんだと思ってください。
人間の目から見たら同じに見える値でも倍精度少数のbit配列は異なっていれば等価と評価できない不安定なものです。

Cよりも上位の言語では、小数点以下もintのように整数値で表したdecimalという型があります。
これで同じ計算をしてみると以下のようにアウトプットされます。

1 : 2
2 : 1.75
3 : 1.7321428571428571428571428571
4 : 1.732050810014727540500736377
5 : 1.7320508075688772952543539461
6 : 1.7320508075688772935274463415
7 : 1.7320508075688772935274463415
...

以降全て結果は1.7320508075688772935274463415になります。
Wikipediaに乗ってるルート3の値は以下のようになっていますが、計算できてるところまでは一致していますね。

1.732050807568877293527446341505872366942805253

C#のdecimalは精度が固定なのでこれ以上の計算はできないのですが、decimalだって元々繰り返し処理の中で循環小数が現れる時点で誤差を含んでいます。
double型を使うと値が変わり続けているのは、精度が足りないため誤差が大きくなり、その誤差の中で結果がブレてしまうために値が変わり続けているように見えるわけです。

大手の作る複雑な計算式の演算を行ってくれるものがどうやって解決しているかまでは分かりませんが、可能な限り式を展開して2進数的に無理な計算が行われる回数を減らすことによって精度を上げているとか、そんなことをしているんじゃないかと思います。

丸めても現実的には困らない精度までは結果を出すことができるのですが、コンピューターでも無理数や循環小数の計算というのは存外難しいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/03 15:41

    えーーと・・・
    15桁を超えると四捨五入されるということでしょうか?

    キャンセル

  • 2017/03/03 17:28

    そうですね。
    指数部との演算上15桁を超える数値がたまたまびしっと表現できる場合もあると思いますが。

    この15桁の数値というのは52bitの仮数部に含まれている値です。
    52bitで表現できる値は2^52乗=16桁の途中に終わるぐらいなので、有効桁数15桁がすっぽり収まる形になるわけです。

    15桁までの値を最初に定義しているのであれば仮数部にすっぽり値も入りますし、10ずつ割っていっても指数の変動で値をシフトできるので値が正確に表現できるわけです。ただ実際の演算ではもっと汚いビットの内情になっているのでこんな風にはならないと思います。

    なので繰り返しになりますが近似値である、というわけです。

    キャンセル

  • 2017/03/03 17:39

    分かりました。
    ありがとうございます。

    キャンセル

+1

見つけてきただけで一切の検証はしていません。
bigfloat

BigFloat の作成は研究している人も多いので、自分で作るよりも探した方が早いかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/03 12:27

    調べてみます。
    ありがとうございます。

    キャンセル

  • 2017/03/03 15:22

    あなたのお作りになろうとしている、長い桁の小数を表せるデータ型はよく BigFloat と呼ばれます。リンク先は C での実装です。構造体を使って表現しています。ソースをご覧になれば、自作される場合でも役立つと思います。

    キャンセル

  • 2017/03/03 15:36

    分かりました。

    キャンセル

0

引用テキストここでdoubleよりもっと大きい桁を扱える変数を自作する方法を教えて下さい。

doubleより大きい変数(もしくはシステムが許す最大変数)を設けるのは困難ではと思います。単に演算結果を求めたいなら変数を複数使って疑似的に行うことはできると思います。それより、演算結果を入れる変数がないとどうしようもないですが。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/03 12:27

    やはり難しいんですね。

    キャンセル

0

参考情報

...
多倍長演算の実装の基本は、筆算での計算方法です。 
一桁同士の足し算、引き算、掛け算(九九の表) があれば、筆算でいくらでも大きな数での計算が 紙の上で行えますよね。 
その方法を 配列をつかって行うのです。 
...

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/07 01:39

    ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.63%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る