セルで計算すると結果は、
3,115,855,702,159,990
ですが、
3,115,855,702,159,992
と計算して欲しい。。(1桁目は、0でなくて2)
実は、小さな数と大きな数の足し算をするため、
有効数字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
たとえば三桁ずつ区切って計算してみては?
# 桁上がりの処理が必要になりますが…
--
赤煉瓦
セルに返された値(文字列)を利用して加減乗除を行うための関数
例です。(エラー処理なし)
関数名、関数型、引数型を変更しました。
' 掛け算
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
28 桁(+α)で十分だったのでしょうか?
Excel とは関係なくなってしまいますが、2700桁の精度で整数演算が
可能な UBASIC なんていうのもありますので、必要なら WEB で検索
してみるのもよろしいかと。
--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp
当方の目的の計算は、大きな数(0~10^30程度)と小さな数(1以下の正数:
0.9975・・など有効数字10桁程度)の乗算の結果の合算(10000個程度)で、
計算結果は0以上1以下となる事は分かっていますが、
数値を得る為に計算してみると10^10を上回ってしまうのです。計算の順番を工
夫もしていますが、計算途中の変数の有効数字を越えることによる計算誤差を充分に
小さくする事ができません。
エクセルや、VBAの範囲を越えてしまうかもしれません。
問題を整理していますが、
C++クラスで有効数字の大きな変数と乗算和算を定義して解決しようかとも考えてい
ます。
・有効数字の大きな数のクラス定義に関する参考書やHPをご存知でしょうか?
・この質問をすべき適切なニュースグループや掲示板をご存知でしたら、教えて下さ
い。?
Miyahn さん
いろいろと、ご心配頂きありがとうございます。
Joe
は訂正です。次のとおり。
当方の目的の計算は、大きな数(0~10^30程度の正の数または負の数)と小さ
な数
======
===
・・・
正の数と負の数の合算で合計1未満の正の数になるのです。(筈なのです。)
Joe
"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
そもそもこの時点で、有効数字は10桁程度しかないと思います。
---
nakashima michio
> >> 当方の目的の計算は、大きな数(0~10^30程度)と小さな数(1以下
> の正数:
> >> 0.9975・・など有効数字10桁程度)の乗算
> ~~~~~~~~~~~~~~~~~~~~~~~~
> >>の結果の合算(10000個程度)で、
>
> そもそもこの時点で、有効数字は10桁程度しかないと思います。
そうなんです。有効数字が足りないのが問題です。
例えば、有効数字3桁づつの正負の数の合計、
1234.99 - 1233.11 = 1.88
は、有効数字がありません。誤差です。
ちなみに結果の有効数字は、3桁もあれば、充分なんです。
Joe
> > >> 0.9975・・など有効数字10桁程度)の乗算
> > ~~~~~~~~~~~~~~~~~~~~~~~~
> > >>の結果の合算(10000個程度)で、
> >
> > そもそもこの時点で、有効数字は10桁程度しかないと思います。
>
> そうなんです。有効数字が足りないのが問題です。
> 例えば、有効数字3桁づつの正負の数の合計、
> 1234.99 - 1233.11 = 1.88
>
> は、有効数字がありません。誤差です。
ようは、どのような精度で計算しようが、そもそも有効数字が10桁しかないの
ですから
計算の精度を高めるためにエクセルで工夫の使用がありません。
もととなる計算式のたてかたを工夫すれば、そうした問題は回避できることも
ありますから、
データの形と計算式を明示して、
fj.sci.mathあたりに投稿してみてはどうでしょう。
---
nakashima michio
うっかり流し読みして間抜けなフォローをつけてたようです。> 私
計算途中で桁落ちするんじゃなくて、元の数字の有効桁が少なかった
んですね。
これじゃ、どうやっても無理でしょうね。
--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp
> ようは、どのような精度で計算しようが、そもそも有効数字が10桁しかないの
> ですから
> 計算の精度を高めるためにエクセルで工夫の使用がありません。
文意がよく分かりませんでしたが、何度か読み返して了解しました。
有効数字3桁の結果を得る為には、正負の合算時には、有効数字桁数が、少なくとも
少数3位をカバーする事が必要ということですね。すなわち、使用する数の有効数字
桁数は、最低33は欲しい、ということでしょうか。
(1以下の正数の有効数字は10桁程度と書きましたが、調整可能です。)
Excelでは目的の計算を完結するというより、計算途中の検算で活用するつもりで
す。
問題を整理したいと思います。
○小数点以下5桁の有効数字が必要な場合、10^30オーダーの数を用いるなら
ば、
用いる数の有効数字は、35桁は欲しい。
○セルの有効数字は、15桁。variant型の変数を用いれば有効数字28桁は得られる。
疑問1.エクセルに有効数字35桁の数を認識させる事はできるか?数値の渡し方は?
あらかじめ、桁分けする必要があるか?
エクセルには、ユーザー定義のDLL関数での計算結果を渡します。
疑問2 ユーザー定義HugeIntは、Doubleの配列で、9桁区切りに変えても、問題無い
でしょうか?
(数字の表示には、複数セル必要でしょうから。配列要素を減らしたい。)
Joe
そうです。
「大きい数 かける 有効数字10桁の数」
の有効数字は10桁ですから、どのように計算をしても、それ以上の精度を求め
ることはできません。
nakashima>
>もととなる計算式のたてかたを工夫すれば、そうした問題は回避できること
も
>ありますから、
と書いたのは、
-----
たとえば、
その大きい数を平均とその差の和に分けて、計算の順序を変えるだけで、意味
のある結果を出すのに必要な有効桁数が減ることがあることがあります。
1002-1001
を計算したいときに、
(1000+2)-(1000+1)と書き直せば、
実際の計算は、2-1と一桁の計算でよいわけです。
------
Joeさんの場合おそらくここまで単純なことではないのでしょうが、物理や工
学などの分野では、こうした工夫はよく行うことなので、そういう発想で知恵
を求めてみてはどうかということです。
--
nakashima
計算の元となる数値の有効桁数は、その通りで良いと思いますが、
以前のフォローで示したようなユーザー定義型で、簡易的に実現するため
には、全て整数として取り扱うことになるかと思いますので、ユーザー
定義型に格納可能な桁数は、70桁以上にする必要があると考えます。
(35桁同士で掛け算した結果を納めるため)
> 疑問1.エクセルに有効数字35桁の数を認識させる事はできるか?
> 数値の渡し方は?
> あらかじめ、桁分けする必要があるか?
> エクセルには、ユーザー定義のDLL関数での計算結果を渡します。
あらかじめ桁分けするか、文字列型で渡すことになると思います。
わざわざ、Excel で計算するより、C++ だけで実現する方が簡単なような
気がしますね。
> 疑問2 ユーザー定義HugeIntは、Doubleの配列で、9桁区切りに変えても、
> 問題無いでしょうか?
Doubleで 9桁区切りだと、掛け算の際に 15桁の有効数字に丸められるので、
別途 Variant 型の一時変数が必要になり、複雑になると思います。
--
Miyahn?犬年うまれ
HQF0...@nifty.ne.jp
ここでは、エクセルの機能についての質問の場と思いますので、
エクセルについての質問を、質問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
"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@何回も推敲しているつもりだが文章を書くのは難しい
# 当方も、一応試しにコードを書いてみてからフォローしておりますので、
# 少しは"想像"だけでなく、お試しになってから投稿されたらいかがかと。
下記は 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
> では、1以下の正数の有効数字が35桁を確保できる状況では、どうでしょう?
EXCELの通常の設定などでは無理で。VBAを使用する
Miyahnさんのフォローなどの方向で解決可能だと思います。
--
nakashima michio
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
> 下記は Variant 型をユーザー定義型の要素にしてでっち上げた、35桁の
> "整数"同士の掛け算をするコード例です。
参考にさせていただきました。目的の計算もほぼ目途が立ちました。
3桁区切りで25個のInteger配列と符号を示す変数からなる変数型を用意して、
関連の関数は、文字列からの代入や、double型との変換、
ユーザー定義型同士の和算(減算)乗算、double型との和算乗算、桁シフト等
必要なものに絞りましたが20個弱の関数を定義しました。いまのところC++です。
書いてみたら、なぜ実数型ではなくて整数型なのか理解できました。^^
文字列の操作についても勉強になりました。
これで、整数同士の和差積は有効数字70桁以上を確保できました。
計算に使う各関数の修正とテストも終わり、じきに目的の計算ができると思います。
Miyahnさん、nakashimaさん適切なアドバイス、ありがとうございました。
Joe