Excel
VBA
PConline
演算誤差
配列数式

【悲報】“達人”芳坂和行氏に学ぶ、エクセル「演算誤差」対策講座がPC Onlineから消えていた

PC ONLINEのサイトから衝撃の講座 EXCEL演算誤差対策講座が2016年8月以降に削除されたようだ。
しかし、この講座 EXCEL 2007くらいを対象にしているが、EXCEL2016でもあっさり発現してしまう。どうせEXCELがこの世から消えるまでこれは治らないので、マイクロソフトから消されたのだろうか。(追記ただし関数は改善するときもあるらしい)
とりあえずリンクとアーカイブを示し、主要な点を補い、オリジナルのマクロを添付した。(入力がめんどくさいからね。)
とにかく
税率、利率を乗除する計算、小数点があって、桁数が極端に違う計算は必ず誤差が出る。
VLookUp,IFで地雷が爆発しやすい
と思っておくと間違いない。
なので、
Roundを使う
1セルで複雑な計算を1度に計算しない
というのが基本。

元のURL

http://pc.nikkeibp.co.jp/pc21/special/gosa/eg1.shtml
http://pc.nikkeibp.co.jp/pc21/special/gosa/eg2.shtml
http://pc.nikkeibp.co.jp/pc21/special/gosa/eg3.shtml
http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml

WebArchive

http://web.archive.org/web/20160413003500/http://pc.nikkeibp.co.jp/pc21/special/gosa
http://web.archive.org/web/20160815202704/http://pc.nikkeibp.co.jp/pc21/special/gosa/eg1.shtml
http://web.archive.org/web/20160807013422/http://pc.nikkeibp.co.jp/pc21/special/gosa/eg2.shtml
http://web.archive.org/web/20160726032410/http://pc.nikkeibp.co.jp/pc21/special/gosa/eg3.shtml
http://web.archive.org/web/20160808054439/http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml

まとめのまとめ

第1回のまとめ

  • 小数点以下の数には誤差がある。

丸写しは芸がないので、実際に演算誤差を発生させるマクロを組みました

Macro1.BAS
\#If VBA7 then
 Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
\#Else  
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
\#End If

Sub Macro1()
Range("A1:B3").Clear
Range("A1").Select: Columns("A:A").ColumnWidth = 8.38: DoEvents: Sleep 500
ActiveSheet.Range("A1").Formula = "=1.9-1.8": Sleep 500
Range("A1").Select
Columns("A:A").ColumnWidth = 41
Range("A1").Select
With Range("A1")
.NumberFormatLocal = "0.00": Range("A3").Value = Len(CStr(Range("A1").Value)) - 2
.NumberFormatLocal = "0.000": Sleep 500: Range("A3").Value = 3
.NumberFormatLocal = "0.0000": Sleep 500: Range("A3").Value = 3 + 1
.NumberFormatLocal = "0.00000": Sleep 500: Range("A3").Value = 3 + 2
.NumberFormatLocal = "0.000000": Sleep 500: Range("A3").Value = 3 + 3
.NumberFormatLocal = "0.0000000": Sleep 500: Range("A3").Value = 3 + 4
.NumberFormatLocal = "0.00000000": Sleep 500: Range("A3").Value = 3 + 5
.NumberFormatLocal = "0.000000000": Sleep 500: Range("A3").Value = 3 + 6
.NumberFormatLocal = "0.0000000000": Sleep 500: Range("A3").Value = 3 + 7
.NumberFormatLocal = "0.00000000000": Sleep 500: Range("A3").Value = 3 + 8
.NumberFormatLocal = "0.000000000000": Sleep 500: Range("A3").Value = 3 + 9
.NumberFormatLocal = "0.0000000000000": Sleep 500: Range("A3").Value = 3 + 10
.NumberFormatLocal = "0.00000000000000": Sleep 500: Range("A3").Value = 3 + 11
Range("A2").Value = "演算誤差が発生しました!!"
Range("A1").Interior.Color = vbRed
.NumberFormatLocal = "0.000000000000000": Sleep 500: Range("A3").Value = 3 + 12
.NumberFormatLocal = "0.0000000000000000": Sleep 500: Range("A3").Value = 3 + 13
.NumberFormatLocal = "0.00000000000000000": Sleep 500: Range("A3").Value = 3 + 14
.NumberFormatLocal = "0.000000000000000000": Sleep 500: Range("A3").Value = 3 + 15
End With
End Sub
  • 計算方法と数によって誤差は見えたり見えなかったりする。

= IF(0.3-0.2=0.1,"y","n") y
= IF(0.3-0.2 -0.1 =0,"y","n") n

CompareERR.Bas
\#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
\#Else
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
\#End If
Sub CompareErr()
If MsgBox("Clear All OK ? (Cancel is Cancel)", vbOKCancel) = vbCancel Then Exit Sub
ActiveSheet.UsedRange.Clear
Range("a1").Select
ActiveCell.FormulaR1C1 = "=IF(0.3-0.2=0.1,""y"",""n"")"
Range("A2").Select
ActiveCell.FormulaR1C1 = "=IF(0.3-0.2-0.1=0,""y"",""n"")"
Range("A2").Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 255
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Range("B2").Select
ActiveCell.FormulaR1C1 = "!!": Sleep 1000
Range("B1").Select
ActiveCell.FormulaR1C1 = "0.3"
Range("C1").Select
ActiveCell.FormulaR1C1 = "-"
Range("D1").Select
ActiveCell.FormulaR1C1 = "0.2"
Range("E1").Select
ActiveCell.FormulaR1C1 = "="
Range("F1").Select
ActiveCell.FormulaR1C1 = "0.1"
Range("B2").Select
ActiveCell.FormulaR1C1 = "0.3"
Range("C2").Select
ActiveCell.FormulaR1C1 = "-"
Range("D2").Select
ActiveCell.FormulaR1C1 = "0.2"
Range("E2").Select
ActiveCell.FormulaR1C1 = "-"
Range("F2").Select
ActiveCell.FormulaR1C1 = "0.1"
Range("G2").Select
ActiveCell.FormulaR1C1 = "="
Range("H2").Select
ActiveCell.FormulaR1C1 = "0"
Range("G2").Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Range("E1").Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Range("I1").Select: Sleep 2000
ActiveCell.FormulaR1C1 = "←EXCELはこれが等しいのに"
Range("I2").Select
ActiveCell.FormulaR1C1 = "←EXCELではこれは0ではない!!!"
MsgBox "式を詳しく見てみるよ!", vbOKOnly, "Go TO Next"
Range("A3").Select
ActiveCell.FormulaR1C1 = "0.3-0.2"
Range("A4").Select
ActiveCell.FormulaR1C1 = "を下に入れる"
Range("A5").Select
ActiveCell.FormulaR1C1 = "=0.3-0.2"
Range("A5").Select
Selection.Copy
Range("A7").Select
ActiveSheet.Paste
Range("A6").Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "幅を広げて桁数を増やしてみる"
MsgBox "幅を広げて桁数を増やしてみる OK"
Range("A6").Select
Columns("A:A").ColumnWidth = 32.5
Range("A7").Select
Selection.NumberFormatLocal = "0.00": Sleep 300
Selection.NumberFormatLocal = "0.000": Sleep 300
Selection.NumberFormatLocal = "0.0000": Sleep 300
Selection.NumberFormatLocal = "0.00000": Sleep 300
Selection.NumberFormatLocal = "0.000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000": Sleep 300
MsgBox "ふやすよー", vbOKOnly, "まだまだ"
Selection.NumberFormatLocal = "0.00000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000000000000": Sleep 300
Range("A8").Select
ActiveCell.FormulaR1C1 = "やっぱりゼロか。桁を戻そう"
MsgBox "ゼロなので桁を戻します"
MsgBox "OK"
Range("A7").Select
Selection.NumberFormatLocal = "0.0"
Columns("A:A").ColumnWidth = 19.5
Range("A9").Select
ActiveCell.FormulaR1C1 = "0.3-0.2=0.1": Sleep 1000
Range("A9").Select
ActiveCell.FormulaR1C1 = "0.3-0.2-0.1"
Range("A4").Select
Selection.Copy
Range("A10").Select
ActiveSheet.Paste
Range("A11").Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "=0.3-0.2-0.1"
Range("A6").Select
Selection.Copy
Range("A12").Select
ActiveSheet.Paste
Range("A11").Select
Application.CutCopyMode = False
Selection.Copy
Range("A13").Select
ActiveSheet.Paste
Columns("A:A").ColumnWidth = 27.13
Range("A13").Select
Application.CutCopyMode = False
MsgBox "桁を増やします"
Selection.NumberFormatLocal = "0.00": Sleep 300
Selection.NumberFormatLocal = "0.000": Sleep 300
Selection.NumberFormatLocal = "0.0000": Sleep 300
Selection.NumberFormatLocal = "0.00000": Sleep 300
Selection.NumberFormatLocal = "0.000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000000000": Sleep 300
Range("B5").Select
Columns("A:A").ColumnWidth = 31.5
Range("A13").Select
Selection.NumberFormatLocal = "0.000000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000000000000": Sleep 300
Columns("A:A").ColumnWidth = 36.88
Selection.NumberFormatLocal = "0.000000000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.0000000000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000000000000000000": Sleep 300
Columns("A:A").ColumnWidth = 42.75
Selection.NumberFormatLocal = "0.0000000000000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.00000000000000000000000000000000000": Sleep 300
Selection.NumberFormatLocal = "0.000000000000000000000000000000000000": Sleep 300
Range("A14").Select
ActiveCell.FormulaR1C1 = "やっぱりゼロ!"
Range("A15").Select
ActiveCell.FormulaR1C1 = "0.3-0.2-0.1=0"
Range("A15").Select
Selection.Copy
Range("A16").Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "=0.3-0.2-0.1=0": Sleep 2000
Range("A16").Select
ActiveCell.FormulaR1C1 = "'=0.3-0.2-0.1=0を下に入れてみる": Sleep 300
Range("A16").Select
Selection.Copy
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "'=0.3-0.2-0.1=0を下に入れてみる": Sleep 300
Range("A17").Select
ActiveCell.FormulaR1C1 = "等しいならTrue、等しくないならFalse": Sleep 1000
Range("A18").Select
ActiveCell.FormulaR1C1 = "どうなる": Sleep 300
MsgBox "どうなる"
Range("A18").Select
ActiveCell.FormulaR1C1 = "どうなる?": Sleep 1000
MsgBox "どうなる????"
Range("A19").Select
ActiveCell.FormulaR1C1 = "=0.3-0.2-0.1=0"
Range("A20").Select
ActiveCell.FormulaR1C1 = "等しくな---------い!"
Range("A20").Select
ActiveCell.FormulaR1C1 = "False!等しくな---------い!"
MsgBox "The End", vbOKOnly, "Oh My God!"
End Sub
  • 整数化すれば誤差のない計算ができる。
  • 整数化するには、必要な桁数だけ10倍、100倍などした後、ROUND関数で小数点以下を四捨五入する。 E3セル =4.3-4.2 ならば = Round(E3*10,0)/10

第2回のまとめ

  • 誤差のある数には、小数点以下の数、時間のシリアル値、パーセント、15桁を超える数がある。
  • 誤差はセルの中だけでなく、数式や関数の計算の中でも発生する。 ※ただし =STDEVP(50000000,50000001) はEXCEL2016では修正されているようだ。(おそらくEXCEL2007)

Excel の統計関数 STDEVPA と STDEVP の違い
この資料では、Microsoft Excel の STDEVPA 関数と、それと密接な関係のある STDEVP 関数との違いについて説明します。特に、Microsoft Office Excel 2007 および Microsoft Office Excel 2003 の STDEVPA 関数の計算結果と以前のバージョンの Excel の STDEVPA 関数の計算結果がどのように異なるかという点について説明します。

FuncErr.BAS
Sub FuncErr()
If MsgBox("Clear All OK ? (Cancel is Cancel)", vbOKCancel) = vbCancel Then Exit Sub
ActiveSheet.UsedRange.Clear
    Columns("A:A").ColumnWidth = 61.75
    Range("A1").Select
    ActiveCell.FormulaR1C1 = "計算の中で誤差が発生"
    Range("A2").Select
    Columns("B:B").ColumnWidth = 49.13
    Range("B2").Select
    ActiveCell.FormulaR1C1 = "'=IF((41/10-4)*10>=1,""大きい"",""小さい"")"
    Range("A2").Select
    ActiveCell.FormulaR1C1 = "=IF((41/10-4)*10>=1,""大きい"",""小さい"")"
    Range("A3").Select
    ActiveCell.FormulaR1C1 = "=41/10"
    Range("A3").Select
    Selection.NumberFormatLocal = "0_);[赤](0)"
    Selection.NumberFormatLocal = "0.0000000000_);[赤](0.0000000000)"
    Range("A3").Select
    Selection.Copy
    Range("A4").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
    Range("B3").Select
    ActiveCell.FormulaR1C1 = "'41/1"
    Range("B3").Select
    ActiveCell.FormulaR1C1 = "'41/10"
    Range("A4").Select

    Selection.NumberFormatLocal = _
        "0.000000000000000000000000000000000_);[赤](0.000000000000000000000000000000000)"
    Range("A4").Select
    Selection.ClearContents
    Range("A4").Select
    ActiveCell.FormulaR1C1 = "=41/1"
    Range("A4").Select
    ActiveCell.FormulaR1C1 = "=41/10-4"
    Range("B4").Select
    ActiveCell.FormulaR1C1 = "'41/10-4=0.1"
    Range("B5").Select
    ActiveCell.FormulaR1C1 = "'(41/10-4)*10=1"
    Range("A5").Select
    ActiveCell.FormulaR1C1 = "=(41/10-4)*10"
    Range("A5").Select
    Selection.NumberFormatLocal = "0.0"

    Selection.NumberFormatLocal = "0.00000000000000"
    Range("B5").Select
    Selection.Copy
    Range("B6").Select
    ActiveSheet.Paste
    Range("A5").Select
    Application.CutCopyMode = False
    Selection.Copy
    Range("A6").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
    Selection.NumberFormatLocal = "0.000000000000000"
    Range("A7").Select
    ActiveCell.FormulaR1C1 = "実は1ではない"
    Range("A6").Select
    Range("A8").Select
    Range("B8").Select
    ActiveCell.FormulaR1C1 = "'STDEVP(50000000,50000001)"
    Range("A8").Select
    ActiveCell.FormulaR1C1 = "=STDEVP(50000000,50000001)"
    Range("B9").Select
    ActiveCell.FormulaR1C1 = "EXCEL2016 64Bitでは修正されている?"
    Range("B8").Select
End Sub

第3回のまとめ

  • 誤差対策の方法には、整数化、微小値を使う方法、ROUND 関数で数をそろえる方法 がある。
  • 計算結果に微小値を加減することで、誤差があっても正確な比較、検索、丸めをすることができる。 『E3>=0.1』という比較を『E3+0.01>=0.1』に変える。つまり、計算結果に小さな数を足して、少しだけ大きな数にする  微小値の大きさは、誤差より大きく、数の変化の単位より小さい範囲にする。普通は数の変化の単位の10分の1で良い。 「数の単位が 0.1 だから、その10分の1ということで、0.01 を使っているわけですね」 「エクセルでは 15 桁まで正確に計算できるから、計算で使う数の 16 桁目を誤差の最大値と考えればいいの。例えば『4.3-4.2』という計算では『4.3』と『4.2』と計算結果の『0.1』を使うよね。この中で一番大きい『4.3』の 16 桁目の大きさ、つまり 0.000000000000001 が一回の計算で発生する誤差のおよその最大値になる」 -「丸めの処理でも微小値が使えるよ。例えば、A1 に『=4.3-4.2』、A2 に『=ROUNDDOWN(A1,1)』と入れると答えは『0』になってしまうけれど、数の変化の単位が 0.1 だとしたら、その10分の1の『0.01』を足して『=ROUNDDOWN(A1+0.01,0)』にすれば答えは『0.1』になる」

ROUND関数で数をそろえる方法
ハル
「ROUND 関数で数をそろえるというのは、どんな方法ですか?」
エリカ
「例えば『ROUND(E3,1)>=ROUND(0.1,1)』のように、両方の数を小数点以下1桁に四捨五入してから比較するの。『ROUND(0.1,1)』は『0.1』と同じ数になるから『ROUND(E3,1)>=0.1』でもいいよ」

「オートフィルでも誤差が出るんですね。気を付けます」

AutoFillErr.BAS
\#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
\#Else
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
\#End If
Sub AutofilErr()
    Range("A2").Select
    Selection.ClearContents
    Selection.End(xlUp).Select
    Range("A2").Select
    ActiveCell.FormulaR1C1 = "7.1"
    Range("A3").Select
    ActiveCell.FormulaR1C1 = "7.2"
    Range("A2:A3").Select
    Selection.AutoFill Destination:=Range("A2:A11"), Type:=xlFillDefault
    Range("A2:A11").Select
    Range("A11").Select
    Selection.NumberFormatLocal = "0.00"": Sleep 500"
    Selection.NumberFormatLocal = "0.000"": Sleep 500"
    Selection.NumberFormatLocal = "0.0000"": Sleep 500"
    Selection.NumberFormatLocal = "0.00000"": Sleep 500"
    Selection.NumberFormatLocal = "0.000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.0000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.00000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.0000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.00000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.000000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.0000000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.00000000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.000000000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.0000000000000000"": Sleep 500"
    Selection.NumberFormatLocal = "0.00000000000000000"": Sleep 500"
End Sub
  • 「表示桁数で計算する」オプションを使うとセルの数値や計算結果を自動的に丸めることができる。
PrecisAsDips.BAS
Sub PrecisAsDips()
ActiveWorkbook.PrecisionAsDisplayed = True
End Sub

「『9000.05085』ですか… あれ? 『9000.05084999999』になりました… どういうことですか?」

Num9K.BAS
Sub Num9K()
If MsgBox("Clear All OK ? (Cancel is Cancel)", vbOKCancel) = vbCancel Then Exit Sub
    ActiveSheet.UsedRange.Clear
    Range("A1").Select
    ActiveCell.FormulaR1C1 = "9000.05084999999"
    Range("A1").Select
    Selection.NumberFormatLocal = "0.0000000000000000000"
    Selection.NumberFormatLocal = "0.000000000000000000"
    Columns("A:A").ColumnWidth = 41.5
    Range("A2").Select
    Range("A2").Formula = "=ROUNDDOWN(A1,4)"
    Range("A3").Value = 9000.0509
End Sub
  • 小数点以下の丸めは正確にできないことがある。

第4回のまとめ

  • IEEE 754 浮動小数点演算規格は現在広く使われている数値計算の標準規格。 「IEEE の中のワーキンググループの番号で、規格の番号でもあるの。IEEE 754 は浮動小数点演算の規格。実はこの IEEE 754 規格がエクセルの演算誤差の原因」 ※つまりEXCELは永遠にこの誤差を抱え続ける
  • 浮動小数点数は『(仮数)×(基数)の(指数)乗』という形式で表現された数値のこと。
  • IEEE 754では2進数を使うため、ほとんどの10進小数は正確に表現できない。

演算誤差対策のない関数

fnIntax01.BAS
Function fnIntax01(Price As Double, taxrate As Double) As Double
'演算誤差対策なし
fnIntax01 = Fix(Price * taxrate)
End Function
  • VBA の通貨型や10進型では、誤差のない10進小数を格納できる。

 演算誤差のない関数。
 ただし整数になる。
 Priceに価格、Taxrateに税率(0.08 or 8% )を代入する

fnIntax03.BAS
Function fnIntax03(Price As Double, taxrate As Double) As Double
fnIntax03 = Fix(CCur(Price) * CCur(taxrate))
End Function
fnIntax04.BAS
Function fnIntax04(Price As Double, taxrate As Double) As Double
fnIntax04 = Fix(CDec(Price) * CDec(taxrate))
End Function

出だしはこんな感じ

◆“達人”芳坂和行氏に学ぶ、エクセル「演算誤差」対策講座
皆さんは、エクセルが“計算が苦手”ということをご存じでしょうか? 表計算ソフトが計算ミスをするなんて、にわかには信じられないことですが、実際にエクセルは、「小数」の計算において、間違った答えを出すことが稀にあります。実はこれ、パソコンが数値を計算する仕組みそのものに由来する現象で、「演算誤差」や「丸め誤差」などと呼ばれるもの。文字通り、計算結果に「誤差」が生じ、正しい結果が求められないという困った問題なのです。に由来する現象で、「演算誤差」や「丸め誤差」などと呼ばれるもの。文字通り、計算結果に「誤差」が生じ、正しい結果が求められないという困った問題なのです。
「コンピューターなら正確だ」と信じているからこそ、エクセルを使って計算しているのに、それが信じられないとすれば、私たちは一体どうすればよいのでしょうか?
そこで日経PC21では、この「演算誤差」によるミスを防ぐための“対策講座”を、ホームページ限定で開講することにしました。講師は、エクセルの“達人”芳坂和行氏。第3回表計算大会で「技能賞」、第5回表計算大会で「エクセル賞」を獲得した名うての実力者です。
「演算誤差」の問題も、その仕組みを理解し、対策のポイントをきちんと押さえれば、確実に対応できるようになります。小数計算で思わぬ失敗をすることがないよう、演算誤差対策のノウハウを身につけましょう。

楽しく読んでいただけるように、講座全体をストーリー仕立てにしています。ここで、登場人物を紹介しておきましょう。

エリカ
(高山 絵里香)
某販売会社に勤める会社員。日経PC21を読んでパソコンを勉強中。難しいことは苦手。でもエクセルはなんとなく面白いと感じている。誤差についても詳しくはないが、聞かれるままに後輩に教える羽目に…
ハル
(松本 波留)
エリカの会社の後輩。新人だが結婚しており、双子の女の子の母。休憩時間にはパソコンで絵を書いて子供たちにメールしている。時間を見つけては資格試験の勉強をしている努力家だが、つい、うとうととしてしまうことも…

追記

配列数式講座も消えていた
https://web.archive.org/web/20050224002535/http://pc21.nikkeibp.co.jp/special/hr/hr1.shtml
https://web.archive.org/web/20050313165321/http://pc21.nikkeibp.co.jp/special/hr/hr2.shtml
https://web.archive.org/web/20050313165538/http://pc21.nikkeibp.co.jp/special/hr/hr3.shtml
https://web.archive.org/web/20050313165645/http://pc21.nikkeibp.co.jp/special/hr/hr4.shtml
https://web.archive.org/web/20050309001106/http://pc21.nikkeibp.co.jp/special/hr/hr5.shtml
https://web.archive.org/web/20050309001106/http://pc21.nikkeibp.co.jp/special/hr/hr6.shtml

このように評価もよいのだが...