t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA 分配法則をど忘れしたので、10000回ループして確認してみた。

先日書いたコードで気になった部分が1点。

Sub 画像トリム()
    
    leftCutSize = 40
    
    With Selection.ShapeRange
        OriginalWidth = .Width
        .LockAspectRatio = msoFalse
        .ScaleWidth (OriginalWidth - leftCutSize) / OriginalWidth, msoFalse, msoScaleFromBottomRight
        .PictureFormat.Crop.PictureWidth = OriginalWidth
        .PictureFormat.Crop.PictureOffsetX = leftCutSize / 2 * -1
    End With
End Sub

ScaleWidthメソッドの第一引数である。

(OriginalWidth - leftCutSize) / OriginalWidth

これって分配法則が成り立つんだったかな。
こう?

(OriginalWidth / OriginalWidth) - (leftCutSize / OriginalWidth)

ということはこう?

1 - (leftCutSize / OriginalWidth)

普段計算してないもんだから、こんなことまで忘れてしまう。
ネットで調べてみようかなと思う前に、コードが閃いた。

そうだ、試そう。

Sub test()
    For a = 1 To 100
     For b = 1 To 100
        Debug.Print (a - b) / a = 1 - (b / a)
    Next b, a
End Sub

結果は、TrueとFalseが半々。

あれ?と思って変数の型を疑ってみた。

Sub test()
    Dim a As Double, b As Double
    For a = 1 To 100
     For b = 1 To 100
        If Not (a - b) / a = 1 - (b / a) Then Debug.Print False
    Next b, a
    Debug.Print "Finish"
End Sub

これでも14個のFalseが発生。

両辺をDecimal型にしてやったらFalseが出なくなった。

Sub test()
    Dim a As Double, b As Double
    For a = 1 To 100
     For b = 1 To 100
        If Not CDec((a - b) / a) = CDec(1 - (b / a)) Then Debug.Print False
    Next b, a
    Debug.Print "Finish"
End Sub

要は精度の問題で不一致が出ていただけで、Decimalできちんと計算すると分配法則は成立しているということが分かった。

今回のケースだとネットで調べた方が早いけれど、「理屈が分からなければ、実際に試してしまえ」ということが出来るのはプログラマの強みである。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。