tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトル桁落ち?
記事No16612
投稿日: 2021/07/22(Thu) 09:10
投稿者M
Visual Basic6を使用していて
下記のプログラムが小数点で8.6と出したいのですが
切りのいい数字になってくれません。

他の数字は、小数点で正常に出ています。。
362.35686-360 =2.35686


何かいい方法は、ございますか?

プログラム

Dim test As Double
  test = 368.6 - 360

8.60000000000002と表示されます。

[ツリー表示へ]
タイトルRe: 桁落ち?
記事No16613
投稿日: 2021/07/23(Fri) 00:37
投稿者魔界の仮面弁士
> Visual Basic6を使用していて
> 下記のプログラムが小数点で8.6と出したいのですが
> 切りのいい数字になってくれません。

Double 型や Single 型は二進小数なので、それは当然ですね。

1 ÷ 2 や 1 ÷ 4 などであれば、二進小数で有限桁となるため、Double に誤差なく格納できます。

1÷10 の結果は、十進小数では有限桁で記録できますよね。
しかし二進小数では循環小数となるため、有限桁では記録できません。

1 ÷ 3 は、三進小数であれば有限桁で問題なく保持できますが、
二進小数や十進小数で保持しようとすると、途中桁で打ち切ることで誤差を含むことになります。

類似の質問として、こちらも参考にしてみてください。
http://hanatyan.sakura.ne.jp/vb60bbs/wforum.cgi?no=16610&reno=16609&oya=16609&mode=msgview&page=0



>  Dim test As Double
>   test = 368.6 - 360

'二進小数のため、誤差を含む
Dim testSingle As Single
testSingle = 368.6! - 360!

'二進小数のため、誤差を含む
Dim testDouble As Double
testDouble = 368.6# - 360#

'十進小数のため誤差はないが、小数点以下4桁までしか保持できない
Dim testCurrency As Currency
testCurrency = 368.6@ - 360@

'十進小数であり、小数点以下の桁数も多いが、その分パフォーマンスが悪い
Dim testDeciaml As Variant
testDeciaml = CDec("368.6") - CDec("360")

'誤差軽減のために十進小数で演算させることが目的なら、
'計算途中で Single や Double を混入させてはいけません。
'数値のデータ型を常に意識してコーディングしましょう。
Debug.Print TypeName(360%)
Debug.Print TypeName(360&)
'Debug.Print TypeName(360^)
Debug.Print TypeName(360!)
Debug.Print TypeName(360#)
Debug.Print TypeName(360@)
Debug.Print TypeName(CDec("360"))
'Debug.Print TypeName(360)
'Debug.Print TypeName(360.0)
Debug.Print TypeName(10 \ 2)
Debug.Print TypeName(10 / 2)

[ツリー表示へ]
タイトルRe^2: 桁落ち?
記事No16614
投稿日: 2021/07/23(Fri) 13:42
投稿者M
> > Visual Basic6を使用していて
> > 下記のプログラムが小数点で8.6と出したいのですが
> > 切りのいい数字になってくれません。
>
> Double 型や Single 型は二進小数なので、それは当然ですね。
>
> 1 ÷ 2 や 1 ÷ 4 などであれば、二進小数で有限桁となるため、Double に誤差なく格納できます。
>
> 1÷10 の結果は、十進小数では有限桁で記録できますよね。
> しかし二進小数では循環小数となるため、有限桁では記録できません。
>
> 1 ÷ 3 は、三進小数であれば有限桁で問題なく保持できますが、
> 二進小数や十進小数で保持しようとすると、途中桁で打ち切ることで誤差を含むことになります。
>
> 類似の質問として、こちらも参考にしてみてください。
> http://hanatyan.sakura.ne.jp/vb60bbs/wforum.cgi?no=16610&reno=16609&oya=16609&mode=msgview&page=0
>
>
>
> >  Dim test As Double
> >   test = 368.6 - 360
>
> '二進小数のため、誤差を含む
> Dim testSingle As Single
> testSingle = 368.6! - 360!
>
> '二進小数のため、誤差を含む
> Dim testDouble As Double
> testDouble = 368.6# - 360#
>
> '十進小数のため誤差はないが、小数点以下4桁までしか保持できない
> Dim testCurrency As Currency
> testCurrency = 368.6@ - 360@
>
> '十進小数であり、小数点以下の桁数も多いが、その分パフォーマンスが悪い
> Dim testDeciaml As Variant
> testDeciaml = CDec("368.6") - CDec("360")
>
> '誤差軽減のために十進小数で演算させることが目的なら、
> '計算途中で Single や Double を混入させてはいけません。
> '数値のデータ型を常に意識してコーディングしましょう。
> Debug.Print TypeName(360%)
> Debug.Print TypeName(360&)
> 'Debug.Print TypeName(360^)
> Debug.Print TypeName(360!)
> Debug.Print TypeName(360#)
> Debug.Print TypeName(360@)
> Debug.Print TypeName(CDec("360"))
> 'Debug.Print TypeName(360)
> 'Debug.Print TypeName(360.0)
> Debug.Print TypeName(10 \ 2)
> Debug.Print TypeName(10 / 2)

ありがとうございました。下記で試して見ます。
'十進小数であり、小数点以下の桁数も多いが、その分パフォーマンスが悪い
Dim testDeciaml As Variant
testDeciaml = CDec("368.6") - CDec("360")

[ツリー表示へ]
タイトルRe^3: 桁落ち?
記事No16615
投稿日: 2021/07/23(Fri) 15:34
投稿者魔界の仮面弁士
> ありがとうございました。下記で試して見ます。
> testDeciaml = CDec("368.6") - CDec("360")

試す場合、演算途中の式に、Single や Double が一切含まれないようにしてくださいね。
誤差が生じた後で CDec や CCur をかけても遅いので…。


> 8.60000000000002と表示されます。

十進数の『8』は、二進数だと「1001」で表されますよね。
十進数の『0.6』は、二進数だと「.1001100110011001100110011……」という循環小数になります。

そのため『8.6』という値を Single や Double の桁数で表現した場合には、
本来の値よりもわずかに小さい値(または少し大きな値)な「近似値」になってしまいます。

参考情報として、具体的に『8.6』の近似前後値を
Single と Double 型の内部表現で表示してみました。蛇足までに。
https://www.vb-user.net/junk/replySamples/2021.07.23.15.18/Single.8.6.png
https://www.vb-user.net/junk/replySamples/2021.07.23.15.18/Double.8.6.png
https://www.vb-user.net/junk/replySamples/2021.07.23.15.18/Double.8.6_full.png

併せてこちらのツールも紹介しておきます。
https://tools.m-bsys.com/calculators/ieee754.php

[ツリー表示へ]