C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: VB6.0 Int関数を使用しての切り捨て処理について


(過去ログ 91 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■54121 / inTopicNo.1)  VB6.0 Int関数を使用しての切り捨て処理について
  
□投稿者/ ペケ (3回)-(2010/10/05(Tue) 18:26:51)

分類:[VB6 以前] 

お世話になっております。

タイトルの件について質問させていただきます。

<開発環境>
Microsoft VisualBasic 6.0 SP5

<質問内容>
以下のようなロジックで切り捨て処理を行いました。

Private Sub Main()
  Dim dblValue1 As Double
  Dim dblValue2 As Double
  Dim dblValue As Double
  Dim dblResult As Double
  Dim intDig  As Integer    ’小数点以下有効桁数
  Dim dblX   AS Double
  
  intDig = 4
  dblX  = (10 ^ intDig)

  dblValue1 = 0.06
  dblValue2 = 0.11
  dblValue = (dblValue1 + dblValue2) / 2   ’※@
  
  dblResult = Int(dblValue * dblX) / dblX   ’※A

End Sub

dblResultに返される値として「0.085」が返却される予定でしたが
実行してみると「0.0849」が返却されます。

デバッグ実行すると※Aを実行した時点で「0.0849」が返されるので
Int関数を疑いましたが、Int関数は少数以下を取り除いた整数を返す
だけなので、問題は※A以外にあるのではないかと思っています。

※@の部分を以下のように変更すると※Aの返却値は「0.085」となります。

 dblValue = 0.085

※@のように計算した結果をDouble型の変数に入れると値がおかしくなるの
でしょうか。

何か解決策があれば教えていただければ幸いです。


宜しくお願い致します。


引用返信 編集キー/
■54123 / inTopicNo.2)  Re[1]: VB6.0 Int関数を使用しての切り捨て処理について
□投稿者/ やじゅ (1757回)-(2010/10/05(Tue) 19:56:30)
やじゅ さんの Web サイト
2010/10/05(Tue) 20:38:50 編集(投稿者)

No54121 (ペケ さん) に返信
> dblResultに返される値として「0.085」が返却される予定でしたが
> 実行してみると「0.0849」が返却されます。
> ※@のように計算した結果をDouble型の変数に入れると値がおかしくなるの
> でしょうか。
>
> 何か解決策があれば教えていただければ幸いです。

コンピュータは2進数で計算しているので、その誤差ですね。基本情報で習うはず。
ちなみに、少数→小数です。

dobule型を使わずに、decimal型を使えば0.085Dという値になります。

VB6は、decimal型を指定できないのでCurrency型ですね。

第4回 演算誤差の正体
http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml
引用返信 編集キー/
■54124 / inTopicNo.3)  Re[1]: VB6.0 Int関数を使用しての切り捨て処理について
□投稿者/ 魔界の仮面弁士 (1852回)-(2010/10/05(Tue) 19:59:14)
2010/10/05(Tue) 20:26:28 編集(投稿者)
# その表記だと VB.NET の話になってしまうかと。>やじゅさん
# まぁ、意味するところは同じですけれどね。


■No54121 (ペケ さん) に返信
> Int関数を疑いましたが、Int関数は少数以下を取り除いた整数を返す
少数→小数という突っ込みはさておき、正確には、
整数を返すのではなく整数部を返す関数ですね。

Int 関数は切り捨て(−∞方向への整数丸め)を行いますが、型変換は行いません。
Fix 関数は切り捨て(0方向への整数丸め)を行いますが、型変換は行いません。
整数型に変換する関数と誤解している人が多いので……一応念のため。


> Microsoft VisualBasic 6.0 SP5
SP6 ではなく?


> 実行してみると「0.0849」が返却されます。
詳細は後述しますが、Int する前の段階で既に誤差が含まれています。たとえば
 dblValue = (dblValue1 + dblValue2) / 2
の段階では、約 0.084999999999999992 近辺の値になっているようですね。


開発環境では、
 dblValue = 0.084999999999999992
と書いても、自動的に
 dblValue = 0.085
に丸められてしまい、その違いがデバッガでも視認しにくいですが、
 Debug.Print CDbl("0.084999999999999992") = CDbl("0.085")
は False となります。


> 何か解決策があれば教えていただければ幸いです。
Double を使うのはやめて、Currency に変更しましょう。
Currency では桁が足りない場合は、10 進型で代用します。
(10進型は、Variant 型の内部形式のひとつです)


'通貨型や10進型を利用する。
Dim Value1 As Currency
Dim Value2 As Currency
Dim Value  As Currency
Dim Result As Currency

Dim intDig As Integer
Dim valX   As Currency

'「^ 演算子」は Double 型の値を返すが、
'今回は演算結果が整数なので、格納誤差は発生しない。
intDig = 4
valX = CCur(10 ^ intDig)

'「@」は通貨型を意味する型宣言文字です。
Value1 = 0.06@
Value2 = 0.11@

'ちなみに 10進型の場合は型宣言文字が無いので、「CDec("0.06")」のようにして
'文字列型を10進型に変換することで対応します。

'なお、Double や Single の値を CDec や CCur することは避けてください。
'(型変換以前に、もともとの値に誤差が含めれている可能性があるため)


'「/ 演算子」は、通貨型に対する演算では Double 型を返しますが、
'内部2進数ゆえ、2 で割っても格納誤差は発生しません。
'(ちなみに「/ 演算子」を 10進型に対して使った場合は、結果も10進型です)
Value = (Value1 + Value2) / 2

'こうすれば、「0.085」という値を取り出すことができます。
Result = Int(Value * valX) / valX


>   dblValue1 = 0.06
>   dblValue2 = 0.11
Double 型で誤差なく処理しようとするのであれば、元となる値も、
2 進小数で誤差なく格納できる範囲でなければ意味がありません。

元データが「近似値」であれば、計算結果もブレてしまいますからね。
下記の資料が参考になるかと思います。
http://salvw.miscnotes.com/index.php/archives/53

引用返信 編集キー/
■54131 / inTopicNo.4)  Re[2]: VB6.0 Int関数を使用しての切り捨て処理について
□投稿者/ ペケ (4回)-(2010/10/06(Wed) 09:20:52)
No54123 (やじゅ さん) に返信
やじゅさん、ご回答ありがとうございます。

> コンピュータは2進数で計算しているので、その誤差ですね。基本情報で習うはず。
そうなんですか。
自分、この業界に未経験で入り、その辺りの知識が欠落してるのです。
※本来勉強しないといけないと思いますが。


> ちなみに、少数→小数です。
ぐふぅ。
IMEが悪いということにしておいてください。


> dobule型を使わずに、decimal型を使えば0.085Dという値になります。
> VB6は、decimal型を指定できないのでCurrency型ですね。
vb.netではdecimal型を使っていたんですが、なるほど、VB6はCurrency型を
使うのですね。


> 第4回 演算誤差の正体
> http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml
自分の中でモヤがかかっていた部分の回答をいただけた気がします。
ありがとうございました。



引用返信 編集キー/
■54134 / inTopicNo.5)  Re[2]: VB6.0 Int関数を使用しての切り捨て処理について
□投稿者/ ペケ (5回)-(2010/10/06(Wed) 09:55:02)
No54124 (魔界の仮面弁士 さん) に返信
魔界の仮面弁士さん、ご回答ありがとうございます。

>>Int関数を疑いましたが、Int関数は少数以下を取り除いた整数を返す
> 少数→小数という突っ込みはさておき、正確には、
> 整数を返すのではなく整数部を返す関数ですね。
> Int 関数は切り捨て(−∞方向への整数丸め)を行いますが、型変換は行いません。
> Fix 関数は切り捨て(0方向への整数丸め)を行いますが、型変換は行いません。
> 整数型に変換する関数と誤解している人が多いので……一応念のため。
その誤解していたうちの一人、でした。

>>Microsoft VisualBasic 6.0 SP5
> SP6 ではなく?
これは自分も疑問に思いました。
VB6の最新サービスパックはSP6だと思うんですが、なぜか今作業している
現場の環境がSP5なのです。


>>実行してみると「0.0849」が返却されます。
> 詳細は後述しますが、Int する前の段階で既に誤差が含まれています。たとえば
>  dblValue = (dblValue1 + dblValue2) / 2
> の段階では、約 0.084999999999999992 近辺の値になっているようですね。
>
>
> 開発環境では、
>  dblValue = 0.084999999999999992
> と書いても、自動的に
>  dblValue = 0.085
> に丸められてしまい、その違いがデバッガでも視認しにくいですが、
>  Debug.Print CDbl("0.084999999999999992") = CDbl("0.085")
> は False となります。
やはりそうですか。
デバッガで見えないのは痛いですが、これからコーディングする上で
この知識があればなんとかなりそうです。


>>何か解決策があれば教えていただければ幸いです。
> Double を使うのはやめて、Currency に変更しましょう。
> Currency では桁が足りない場合は、10 進型で代用します。
> (10進型は、Variant 型の内部形式のひとつです)
>
>
> '通貨型や10進型を利用する。
> Dim Value1 As Currency
> Dim Value2 As Currency
> Dim Value As Currency
> Dim Result As Currency
>
> Dim intDig As Integer
> Dim valX As Currency
>
> '「^ 演算子」は Double 型の値を返すが、
> '今回は演算結果が整数なので、格納誤差は発生しない。
> intDig = 4
> valX = CCur(10 ^ intDig)
>
> '「@」は通貨型を意味する型宣言文字です。
> Value1 = 0.06@
> Value2 = 0.11@
>
> 'ちなみに 10進型の場合は型宣言文字が無いので、「CDec("0.06")」のようにして
> '文字列型を10進型に変換することで対応します。
>
> 'なお、Double や Single の値を CDec や CCur することは避けてください。
> '(型変換以前に、もともとの値に誤差が含めれている可能性があるため)
>
>
> '「/ 演算子」は、通貨型に対する演算では Double 型を返しますが、
> '内部2進数ゆえ、2 で割っても格納誤差は発生しません。
> '(ちなみに「/ 演算子」を 10進型に対して使った場合は、結果も10進型です)
> Value = (Value1 + Value2) / 2
>
> 'こうすれば、「0.085」という値を取り出すことができます。
> Result = Int(Value * valX) / valX
>
>>  dblValue1 = 0.06
>>  dblValue2 = 0.11
> Double 型で誤差なく処理しようとするのであれば、元となる値も、
> 2 進小数で誤差なく格納できる範囲でなければ意味がありません。
>
> 元データが「近似値」であれば、計算結果もブレてしまいますからね。
> 下記の資料が参考になるかと思います。
> http://salvw.miscnotes.com/index.php/archives/53
詳細なサンプルソースありがとうございます。
Currency型について知識が薄いので頂いたURLで勉強したいと思います。

ありがとうございました。

解決済み
引用返信 編集キー/
■54136 / inTopicNo.6)  Re[3]: VB6.0 Int関数を使用しての切り捨て処理について
□投稿者/ 魔界の仮面弁士 (1854回)-(2010/10/06(Wed) 10:28:40)
2010/10/06(Wed) 15:07:52 編集(投稿者)

No54131 (ペケ さん) に返信
>>dobule型を使わずに、decimal型を使えば0.085Dという値になります。
>>VB6は、decimal型を指定できないのでCurrency型ですね。
> vb.netではdecimal型を使っていたんですが、なるほど、VB6はCurrency型を
> 使うのですね。

VB6 でも Decimal(10 進型) は利用できます。ただし As Decimal ではなく、
 Dim v As Variant
 v = CDec("0.085")
のように、Variant 型の変数として管理する事になります。

ちなみに VB6 の Decimal の精度は、VB.NET のそれと同一です。具体的には
小数点位置が 0〜28 の間で可変であり、小数点を除いた数値としては
±79228162514264337593543950335 の範囲をとるという型になっています。


一方 Currency(通貨型) は、Decimal とは違って Variant の一種としてではなく、
プリミティブ型として用意されている点が強みです。
Currency の場合、小数点は 4 桁固定、整数部は最大 15 桁となっており、
値の範囲は -922337203685477.5808 〜 +922337203685477.5807 です。


多くの場合、整数部の桁数は Currency で充分だと思いますので、
小数部の桁数が 4 桁で足りるかどうかで使い分けると良いでしょう。

ただし桁数的には Currency で足りていても、意図的に Decimal が
採用されるケースもあります。それは、「演算結果の型」によるものです。

先のサンプルにもコメントで書いていますが、たとえば、
 Debug.Print TypeName( value1 / value2 )
などを実行した場合、value1 や 2 の型が Currency であったとしても、
除算結果は Currency 型にはなりません。通常は Double になります。

実は「/ 演算子」での除算結果が Double 以外の型になるのは、
Single の除算(結果もSingle)と Decimal の除算(結果も Decimal)だけなのです。
# 分かりにくいのですが、いちおう VB6 のヘルプにも書いてあったりします。


その意味で、除算処理が含まれる場合には、Currency ではなく
あえて Decimal が採用されるケースもあります。


あるいは、「/ 演算子」の代わりに「* 演算子」で処理するという手法もあります。
除算とは異なり、乗算では基本的に元の型が維持されるため、
たとえば「10で割る」処理を「0.1をかける」に書き換えてやれば、
Currency 型のままで演算する事が可能となります。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -