Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

掛算の有効数字桁数を増やしたい

29 views
Skip to first unread message

Joe

unread,
Jul 19, 2002, 6:33:42 PM7/19/02
to
たとえば、
22 × 141,629,804,643,636
を計算すると、正しく計算できません。
有効数字の問題と思いますが、有効数字桁数を増やして
正しい計算をする方法は、ないでしょうか?

セルで計算すると結果は、
3,115,855,702,159,990
ですが、
3,115,855,702,159,992
と計算して欲しい。。(1桁目は、0でなくて2)

実は、小さな数と大きな数の足し算をするため、
有効数字45桁ぐらい欲しいです。


Miyahn

unread,
Jul 19, 2002, 7:41:28 PM7/19/02
to
"Joe" wrote in message news:udXjxT3LCHA.944@tkmsftngp10

> たとえば、
> 22 × 141,629,804,643,636
> を計算すると、正しく計算できません。
*** 中略 ***
> 実は、小さな数と大きな数の足し算をするため、
> 有効数字45桁ぐらい欲しいです。

セルの有効数字は 15 桁なので、セルに結果を数値として入力する
わけにはいきませんし、有効数字 45 桁も実現できませんが、
こんなユーザー定義関数で有効数字 28桁 の掛け算結果の表示を
することは可能です。

Function LargeProduct(A As Double, B As Double) As String
Dim Result As Variant
Result = CDec(A) * CDec(B)
LargeProduct = Str(Result)
End Function

例示されている 141,629,804,643,636 の二乗も計算できます。

--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp

red brick

unread,
Jul 19, 2002, 8:00:58 PM7/19/02
to
Joeさんの<udXjxT3LCHA.944@tkmsftngp10>から

>たとえば、
> 22 × 141,629,804,643,636
>を計算すると、正しく計算できません。
>有効数字の問題と思いますが、有効数字桁数を増やして
>正しい計算をする方法は、ないでしょうか?

 たとえば三桁ずつ区切って計算してみては?

# 桁上がりの処理が必要になりますが…

--
赤煉瓦

Miyahn

unread,
Jul 20, 2002, 9:13:40 AM7/20/02
to
Miyahn より修正&補足フォローです。

> セルの有効数字は 15 桁なので、セルに結果を数値として入力する
> わけにはいきませんし、

セルに返された値(文字列)を利用して加減乗除を行うための関数
例です。(エラー処理なし)
関数名、関数型、引数型を変更しました。

' 掛け算
Function PrdEx(A As Variant, B As Variant) As Variant
PrdEx = Format(CDec(A) * CDec(B), "#,###")
End Function
' 割り算
Function DivEx(A As Variant, B As Variant) As Variant
DivEx = Format(CDec(A) / CDec(B), "#,###")
End Function
' 足し算
Function AddEx(A As Variant, B As Variant) As Variant
AddEx = Format(CDec(A) + CDec(B), "#,###")
End Function
' 引き算
Function SbtEx(A As Variant, B As Variant) As Variant
SbtEx = Format(CDec(A) - CDec(B), "#,###")
End Function

--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp

Joe

unread,
Jul 21, 2002, 1:40:18 AM7/21/02
to
Miyahnさん、マクロ動きました。どうもありがとう。
赤煉瓦さん、次の問題の解決のヒントにします。
ご返事どうもありがとう。

Joe

Miyahn

unread,
Jul 21, 2002, 10:39:25 AM7/21/02
to
"Joe" wrote in message news:e$DF0mHMCHA.2320@tkmsftngp11
> Miyahnさん、マクロ動きました。どうもありがとう。

28 桁(+α)で十分だったのでしょうか?

Excel とは関係なくなってしまいますが、2700桁の精度で整数演算が
可能な UBASIC なんていうのもありますので、必要なら WEB で検索
してみるのもよろしいかと。

--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp

Joe

unread,
Jul 23, 2002, 9:48:44 AM7/23/02
to
> 28 桁(+α)で十分だったのでしょうか?
そうなんです。当初の問題(=計算結果の精度を上げる。)は、まだ解決していない
のです。^^;
ご紹介のUBASICもHPを拝見しましたが、UBASICの対象が整数でしたので、当方の問題
への応用は難しいようです。

当方の目的の計算は、大きな数(0~10^30程度)と小さな数(1以下の正数:
0.9975・・など有効数字10桁程度)の乗算の結果の合算(10000個程度)で、
計算結果は0以上1以下となる事は分かっていますが、
数値を得る為に計算してみると10^10を上回ってしまうのです。計算の順番を工
夫もしていますが、計算途中の変数の有効数字を越えることによる計算誤差を充分に
小さくする事ができません。

エクセルや、VBAの範囲を越えてしまうかもしれません。
問題を整理していますが、
C++クラスで有効数字の大きな変数と乗算和算を定義して解決しようかとも考えてい
ます。

・有効数字の大きな数のクラス定義に関する参考書やHPをご存知でしょうか?
・この質問をすべき適切なニュースグループや掲示板をご存知でしたら、教えて下さ
い。?

Miyahn さん
いろいろと、ご心配頂きありがとうございます。

Joe

Joe

unread,
Jul 23, 2002, 10:32:58 AM7/23/02
to

>当方の目的の計算は、大きな数(0~10^30程度)と小さな数

は訂正です。次のとおり。

当方の目的の計算は、大きな数(0~10^30程度の正の数または負の数)と小さ
な数
                                ======
===
・・・

正の数と負の数の合算で合計1未満の正の数になるのです。(筈なのです。)

Joe

Miyahn

unread,
Jul 23, 2002, 10:49:43 AM7/23/02
to
# お題元に戻しました。
# 同じ内容で頻繁にお題だけ変えるのは良くないと思います。

"Joe" wrote in message news:ueObHBlMCHA.2200@tkmsftngp08


> ご紹介のUBASICもHPを拝見しましたが、UBASICの対象が整数でしたので、当方の問題
> への応用は難しいようです。
>
> 当方の目的の計算は、大きな数(0~10^30程度)と小さな数(1以下の正数:
> 0.9975・・など有効数字10桁程度)の乗算の結果の合算(10000個程度)で、
> 計算結果は0以上1以下となる事は分かっていますが、
> 数値を得る為に計算してみると10^10を上回ってしまうのです。

全体を10^10倍して全て整数として取り扱えば、UBASIC で十分カバーできる
と思うのですが。

演算が、掛け算と足し算だけなら、"赤煉瓦" さんの言うように、桁区切り
をして演算するのもそれほど難しくないと思います。
例えば、
Type HugeInt
Num(15) As Long
End Type
などとユーザー定義型を定義して、その型の変数を定義して値を格納し、
それぞれの演算をユーザー定義関数で作成すれば、整数の取り扱いは結構
簡単そうに思えます。

プログラム言語関係で、WEB 検索されるのなら、キーワードは「BCD」&
「ライブラリ」あたりがよろしいかと思います。
BCD: Binary Coded Decimal

# 141,629,804,643,636 がお金で、自由に使えたらいいのにな~。

--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp


nakashima michio

unread,
Jul 23, 2002, 8:08:02 PM7/23/02
to

>> 当方の目的の計算は、大きな数(0~10^30程度)と小さな数(1以下
の正数:
>> 0.9975・・など有効数字10桁程度)の乗算
~~~~~~~~~~~~~~~~~~~~~~~~
>>の結果の合算(10000個程度)で、

そもそもこの時点で、有効数字は10桁程度しかないと思います。


---
nakashima michio


Joe

unread,
Jul 23, 2002, 8:42:37 PM7/23/02
to
レスありがとうございます。

> >> 当方の目的の計算は、大きな数(0~10^30程度)と小さな数(1以下
> の正数:
> >> 0.9975・・など有効数字10桁程度)の乗算
> ~~~~~~~~~~~~~~~~~~~~~~~~
> >>の結果の合算(10000個程度)で、
>
> そもそもこの時点で、有効数字は10桁程度しかないと思います。

そうなんです。有効数字が足りないのが問題です。
例えば、有効数字3桁づつの正負の数の合計、
  1234.99 - 1233.11 = 1.88
   
は、有効数字がありません。誤差です。

ちなみに結果の有効数字は、3桁もあれば、充分なんです。

Joe

nakashima michio

unread,
Jul 24, 2002, 4:24:51 AM7/24/02
to

"Joe" <jo...@jcom.home.ne.jp> wrote

> > >> 0.9975・・など有効数字10桁程度)の乗算
> > ~~~~~~~~~~~~~~~~~~~~~~~~
> > >>の結果の合算(10000個程度)で、
> >
> > そもそもこの時点で、有効数字は10桁程度しかないと思います。
>
> そうなんです。有効数字が足りないのが問題です。
> 例えば、有効数字3桁づつの正負の数の合計、
>   1234.99 - 1233.11 = 1.88
>    
> は、有効数字がありません。誤差です。

ようは、どのような精度で計算しようが、そもそも有効数字が10桁しかないの
ですから
計算の精度を高めるためにエクセルで工夫の使用がありません。

もととなる計算式のたてかたを工夫すれば、そうした問題は回避できることも
ありますから、
データの形と計算式を明示して、
fj.sci.mathあたりに投稿してみてはどうでしょう。
---
nakashima michio


Miyahn

unread,
Jul 24, 2002, 8:26:54 AM7/24/02
to
"nakashima michio" wrote in message news:OHR3luuMCHA.2372@tkmsftngp11

> > そうなんです。有効数字が足りないのが問題です。
> > 例えば、有効数字3桁づつの正負の数の合計、
> >   1234.99 - 1233.11 = 1.88
> >    
> > は、有効数字がありません。誤差です。
>
> ようは、どのような精度で計算しようが、そもそも有効数字が10桁しかないの
> ですから
> 計算の精度を高めるためにエクセルで工夫の使用がありません。

うっかり流し読みして間抜けなフォローをつけてたようです。> 私
計算途中で桁落ちするんじゃなくて、元の数字の有効桁が少なかった
んですね。
これじゃ、どうやっても無理でしょうね。

--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp

Joe

unread,
Jul 26, 2002, 8:11:57 PM7/26/02
to
nakashima michioさん、Miyahnさんコメントありがとうございます。
夏休みで家族旅行でした。レス遅くなってすいません。

> ようは、どのような精度で計算しようが、そもそも有効数字が10桁しかないの
> ですから
> 計算の精度を高めるためにエクセルで工夫の使用がありません。

文意がよく分かりませんでしたが、何度か読み返して了解しました。
有効数字3桁の結果を得る為には、正負の合算時には、有効数字桁数が、少なくとも
少数3位をカバーする事が必要ということですね。すなわち、使用する数の有効数字
桁数は、最低33は欲しい、ということでしょうか。
(1以下の正数の有効数字は10桁程度と書きましたが、調整可能です。)

Excelでは目的の計算を完結するというより、計算途中の検算で活用するつもりで
す。
問題を整理したいと思います。

○小数点以下5桁の有効数字が必要な場合、10^30オーダーの数を用いるなら
ば、
用いる数の有効数字は、35桁は欲しい。
○セルの有効数字は、15桁。variant型の変数を用いれば有効数字28桁は得られる。

疑問1.エクセルに有効数字35桁の数を認識させる事はできるか?数値の渡し方は?
 あらかじめ、桁分けする必要があるか?
 エクセルには、ユーザー定義のDLL関数での計算結果を渡します。

疑問2 ユーザー定義HugeIntは、Doubleの配列で、9桁区切りに変えても、問題無い
でしょうか?
(数字の表示には、複数セル必要でしょうから。配列要素を減らしたい。)


Joe

nakashima michio

unread,
Jul 27, 2002, 1:09:01 AM7/27/02
to

> 文意がよく分かりませんでしたが、何度か読み返して了解しました。
> 有効数字3桁の結果を得る為には、正負の合算時には、有効数字桁数が、少
なくとも
> 少数3位をカバーする事が必要ということですね。すなわち、使用する数の
有効数字
> 桁数は、最低33は欲しい、ということでしょうか。
> (1以下の正数の有効数字は10桁程度と書きましたが、調整可能です。)

そうです。
「大きい数 かける 有効数字10桁の数」
の有効数字は10桁ですから、どのように計算をしても、それ以上の精度を求め
ることはできません。

nakashima>
>もととなる計算式のたてかたを工夫すれば、そうした問題は回避できること

>ありますから、
と書いたのは、

-----
たとえば、
その大きい数を平均とその差の和に分けて、計算の順序を変えるだけで、意味
のある結果を出すのに必要な有効桁数が減ることがあることがあります。

1002-1001
を計算したいときに、
(1000+2)-(1000+1)と書き直せば、
実際の計算は、2-1と一桁の計算でよいわけです。
------
Joeさんの場合おそらくここまで単純なことではないのでしょうが、物理や工
学などの分野では、こうした工夫はよく行うことなので、そういう発想で知恵
を求めてみてはどうかということです。

--
nakashima

Miyahn

unread,
Jul 27, 2002, 9:25:45 AM7/27/02
to
"Joe" wrote in message news:e9l$dLQNCHA.1632@tkmsftngp09

> 小数点以下5桁の有効数字が必要な場合、10^30オーダーの数を用いる
> ならば、用いる数の有効数字は、35桁は欲しい。

計算の元となる数値の有効桁数は、その通りで良いと思いますが、
以前のフォローで示したようなユーザー定義型で、簡易的に実現するため
には、全て整数として取り扱うことになるかと思いますので、ユーザー
定義型に格納可能な桁数は、70桁以上にする必要があると考えます。
(35桁同士で掛け算した結果を納めるため)

> 疑問1.エクセルに有効数字35桁の数を認識させる事はできるか?
>  数値の渡し方は?
>  あらかじめ、桁分けする必要があるか?
>  エクセルには、ユーザー定義のDLL関数での計算結果を渡します。

あらかじめ桁分けするか、文字列型で渡すことになると思います。
わざわざ、Excel で計算するより、C++ だけで実現する方が簡単なような
気がしますね。

> 疑問2 ユーザー定義HugeIntは、Doubleの配列で、9桁区切りに変えても、
> 問題無いでしょうか?

Doubleで 9桁区切りだと、掛け算の際に 15桁の有効数字に丸められるので、
別途 Variant 型の一時変数が必要になり、複雑になると思います。

--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp

Joe

unread,
Jul 27, 2002, 9:38:05 AM7/27/02
to
nakashima michioさん、文意が通じにくいようですので、言い換えます。
#1以下の正数の有効数字は7/23のコメントでは10桁程度と書きましたが、33桁以上
にすることができます。
nakashimaさんの当初のご指摘は、”計算順序を更に工夫しても入れ替えても有効数
字10桁の数を掛けるのでは、
計算結果の有効数字は3桁さえも確保できない”ということかと理解しました。
では、1以下の正数の有効数字が35桁を確保できる状況では、どうでしょう?

ここでは、エクセルの機能についての質問の場と思いますので、
エクセルについての質問を、質問0を付け加えて再掲します。
部分的なご回答でも歓迎です。

質問0 大きな数(0~10^30程度の正負の数)と小さな数(1以下の正数:
0.9975・・など有効数字35桁)の乗算の結果の合算(10000個程度)は、エ
クセルでは(どうやっても)できないのか?
計算結果は0以上1以下となる事は分かっており、有効数字は3桁必要。

疑問1.エクセルに有効数字35桁の数を認識させる事はできるか?数値の渡し方は?
 あらかじめ、桁分けした配列などで渡す必要があるか?
 エクセルには、ユーザー定義のDLL関数での計算結果を渡します。

疑問2 ユーザー定義型HugeIntは、Doubleの配列で、9桁区切りに変えても、問題無

でしょうか?
(数字の表示には、複数セル必要でしょうから。配列要素を減らしたい。)
※7/23Miyahnさんコメントユーザー定義型


Type HugeInt
Num(15) As Long
End Type

Joe


Joe

unread,
Jul 27, 2002, 10:12:16 AM7/27/02
to
Miyahnさん、親身なコメントありがとうございます。

"Miyahn" <HQF0...@nifty.ne.jp> wrote in message
news:#t#dwEXNCHA.2344@tkmsftngp09...


> わざわざ、Excel で計算するより、C++ だけで実現する方が簡単なような
> 気がしますね。

C++でも完結します。一方で、途中結果の検算はやはりEXCELが使いやすいのです。
今回のように、有効数字漏れなどがある場合は特にC++だけでは、検算しにくいので
Excelが使えれば、重宝します。

> > 疑問2 ユーザー定義HugeIntは、Doubleの配列で、9桁区切りに変えても、
> > 問題無いでしょうか?
> Doubleで 9桁区切りだと、掛け算の際に 15桁の有効数字に丸められるので、
> 別途 Variant 型の一時変数が必要になり、複雑になると思います。

> には、全て整数として取り扱うことになるかと思いますので、ユーザー
> 定義型に格納可能な桁数は、70桁以上にする必要があると考えます。

やはり、long型配列で3桁区切りですか。
すると整数部分が30桁でlong型配列10個、小数部分が35桁で配列12個。
合計でlong型配列は22個は最低必要、余裕を見て12+16個程度のlong型配列を用
意した方が良さそうですね。
long型配列で6桁区切りでは問題ありますか?

和算や乗算は、桁の繰り上がりや繰り下がりがやや面倒ですが、想像がつきます。
表示は、文字列型に変換して1セルで表示、なんてできますか?
3桁づつセル分けするのは、つらいので。


Joe@何回も推敲しているつもりだが文章を書くのは難しい

Miyahn

unread,
Jul 27, 2002, 10:35:41 AM7/27/02
to
"Joe" wrote in message news:uXOfBhXNCHA.1724@tkmsftngp08

> やはり、long型配列で3桁区切りですか。
> すると整数部分が30桁でlong型配列10個、小数部分が35桁で配列12個。
> 合計でlong型配列は22個は最低必要、余裕を見て12+16個程度のlong型配列を用
> 意した方が良さそうですね。
> long型配列で6桁区切りでは問題ありますか?
>
> 和算や乗算は、桁の繰り上がりや繰り下がりがやや面倒ですが、想像がつきます。
> 表示は、文字列型に変換して1セルで表示、なんてできますか?
> 3桁づつセル分けするのは、つらいので。

# 当方も、一応試しにコードを書いてみてからフォローしておりますので、
# 少しは"想像"だけでなく、お試しになってから投稿されたらいかがかと。

下記は Variant 型をユーザー定義型の要素にしてでっち上げた、35桁の
"整数"同士の掛け算をするコード例です。
エラー処理/演算結果の検証はしておりませんし、文字列処理のパフォー
マンスへの配慮もありませんのでご注意。

Const Part As Integer = 5 'ブロック数
Const Fig As Integer = 14 '桁数/ブロック
Private Type HugeInt
Num(Part) As Variant
End Type
Private Sub SetHugeInt(A As HugeInt, NumStr As String)
Dim I As Integer
NumStr = Right(String(Part * Fig, "0") & NumStr, Part * Fig)
For I = Part To 1 Step -1
A.Num(Part - I + 1) = CDec(Mid(NumStr, Fig * (I - 1) + 1, Fig))
Next I
End Sub
Private Function Mul(A As HugeInt, B As HugeInt) As HugeInt
Dim I As Integer, J As Integer, K As Integer
On Error Resume Next
For I = 1 To Part
For J = 1 To Part
K = I + J - 1
Mul.Num(K) = Mul.Num(K) + A.Num(I) * B.Num(J)
Mul.Num(K + 1) = Mul.Num(K + 1) + Int(Mul.Num(K) / 10 ^ Fig)
Mul.Num(K) = Mul.Num(K) - Int(Mul.Num(K) / 10 ^ Fig) * 10 ^ Fig
Next J
Next I
On Error GoTo 0
End Function
Sub Test()
Dim A As HugeInt, B As HugeInt
Dim I As Integer
Dim Result As String
SetHugeInt A, "12345678901234567890123456489012345"
SetHugeInt B, "12345678901234567890123456489012345"
With Mul(A, B)
For I = Part To 1 Step -1
Result = Result & Format(.Num(I), String(Fig, "0"))
Next I
End With
While Mid(Result, 1, 1) = "0"
Result = Mid(Result, 2)
Wend
Debug.Print Result
End Sub

--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp

nakashima michio

unread,
Jul 27, 2002, 5:12:58 PM7/27/02
to
どうもフォローを付け直したのが余計ややこしかったようです。
"Joe" <jo...@jcom.home.ne.jp> wrote
> nakashima michioさん、文意が通じにくいようですので、言い換えます。
つうじております。
> #1以下の正数の有効数字は7/23のコメントでは10桁程度と書きましたが、33桁以

> にすることができます。
Joeさんの求める状況が実際にはそうであったことも理解した上で、あくまで自分の
書いたことを書き直しただけのつもりでした。
(文章がよくわからないとのことだったので)

> では、1以下の正数の有効数字が35桁を確保できる状況では、どうでしょう?
EXCELの通常の設定などでは無理で。VBAを使用する
Miyahnさんのフォローなどの方向で解決可能だと思います。

--
nakashima michio

nakashima michio

unread,
Jul 28, 2002, 4:21:18 PM7/28/02
to
誰か作ってないかなとおもったら、

VB6 Faq & Untique
Q. Currency型よりも大きい範囲の数値を、精度よく計算したい。
http://member.nifty.ne.jp/salv/hp-old/03pc/qvb/03vbpg006.htm
というのを見つけたので、
そこからダウンロードできる
LongCalc.lzhのなかのLongCalc.bas
の中身をそのままモジュールに貼り付けて、

'-------------------------------
Function xSum(ParamArray a())
’ワークシート関数 合計
Dim r, c, Tmp As ShisuuSet
For Each r In a
For Each c In r
Tmp = sAdd(Tmp, JtoS(c.Text))
Next
Next
xSum = StoJ(Tmp)
End Function

Function xAdd(a, b)
’ワークシート関数 加算
Dim na As ShisuuSet, nb As ShisuuSet
na = JtoS(a.Text): nb = JtoS(b.Text)
xAdd = StoJ(sAdd(na, nb))
End Function

Function xMlt(a, b)
’ワークシート関数 減算
Dim na As ShisuuSet, nb As ShisuuSet
na = JtoS(a.Text): nb = JtoS(b.Text)
xMlt = StoJ(sMlt(na, nb))
End Function
'-------------------------------

という関数を追加するとワークシート関数として動きました。
普通の大きさの整数の計算をさせてみましたが、うまく動いているように見えます。

私のpentium3 1Ghz windows2000 excel2000では
45桁*45桁のxMltを1万行処理するのに5分ぐらいでした。

----
nakashima

Joe

unread,
Aug 4, 2002, 4:32:38 PM8/4/02
to
PCのWindowsの再インストールとドライバの再設定に手間取っていて、
ニュースにつなげませんでした。レス遅くなりすいません。

> 下記は Variant 型をユーザー定義型の要素にしてでっち上げた、35桁の
> "整数"同士の掛け算をするコード例です。

参考にさせていただきました。目的の計算もほぼ目途が立ちました。
3桁区切りで25個のInteger配列と符号を示す変数からなる変数型を用意して、
関連の関数は、文字列からの代入や、double型との変換、
ユーザー定義型同士の和算(減算)乗算、double型との和算乗算、桁シフト等
必要なものに絞りましたが20個弱の関数を定義しました。いまのところC++です。

書いてみたら、なぜ実数型ではなくて整数型なのか理解できました。^^
文字列の操作についても勉強になりました。

これで、整数同士の和差積は有効数字70桁以上を確保できました。
計算に使う各関数の修正とテストも終わり、じきに目的の計算ができると思います。

Miyahnさん、nakashimaさん適切なアドバイス、ありがとうございました。

Joe


0 new messages