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

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

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

Re[3]: SQLServer2000→2008R2 へのデータ以降


(過去ログ 126 を表示中)

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

■75335 / inTopicNo.1)  SQLServer2000→2008R2 へのデータ以降
  
□投稿者/ ハルハル (11回)-(2015/03/16(Mon) 18:48:22)

分類:[データベース全般] 

SQLServer2000 から SQLServer2008R2 へ データベースを移行しているのですが、

float型の値が17桁MAXの場合に丸められてしまい困っています。
ex)
-2257.5999999999999 ⇒ -2257.6
546.29999999999995 ⇒ 546.3

(単純に、SQLServer2000でバックアップを作成し、SQLServer2008R2で復元した場合)

どなたか解決策をご存知の方はいらっしゃいませんか?


引用返信 編集キー/
■75337 / inTopicNo.2)  Re[1]: SQLServer2000→2008R2 へのデータ以降
□投稿者/ 魔界の仮面弁士 (240回)-(2015/03/16(Mon) 20:39:34)
No75335 (ハルハル さん) に返信
> float型の値が17桁MAXの場合に丸められてしまい困っています。

float 型に 17 桁もの精度はありませんよ。IEEE754 の浮動小数点数ですから。

Books Online の float(n) 型 の説明を読むと、
 n=1〜24 の場合は 4バイトを消費し、有効桁数は 7 桁
 n=25〜53 の場合は 8バイトを消費し、有効桁数は 15 桁
とあります。最大精度でも 15 桁のはずです。

そもそも、同資料には
 『概数であるため、データ型の範囲に含まれるすべての値を正確に表せるわけではありません。』
の記載があります。細かい誤差を厳密に管理できるような型ではありません。
二進小数で割り切れない値は、有効桁数内の近似値で格納される仕様です。


> ex)
> -2257.5999999999999 ⇒ -2257.6
> 546.29999999999995 ⇒ 546.3

少なくとも VB では、CSng("-2257.5999999999999") と CSng("-2257.6") は同じ値です。CDbl も然り。

バージョンが違うことで、文字列化したときに異なる値に見えてしまうだけで、
実際には同じ値ということはないでしょうか。
引用返信 編集キー/
■75338 / inTopicNo.3)  Re[2]: SQLServer2000→2008R2 へのデータ以降
□投稿者/ 魔界の仮面弁士 (241回)-(2015/03/16(Mon) 21:28:59)
2015/03/16(Mon) 21:53:28 編集(投稿者)

No75337 (魔界の仮面弁士) に追記
>> -2257.5999999999999 ⇒ -2257.6
>> 546.29999999999995 ⇒ 546.3
> バージョンが違うことで、文字列化したときに異なる値に見えてしまうだけで、
> 実際には同じ値ということはないでしょうか。

念のために試算。

たとえば、float(24) の範囲で、「-2257.6」の近似値をバイナリ表現してみます。
有効桁数 24 bit の 2 進小数で表すので、近傍値はこのあたりになります。

 (a) -100011010001.100110011000 → 10進数の -2257.599609375 に相当
 (b) -100011010001.100110011001 → 10進数の -2257.599853515625 に相当
 (c) -100011010001.100110011010 → 10進数の -2257.60009765625 に相当
 (d) -100011010001.100110011011 → 10進数の -2257.600341796875 に相当
 (e) -100011010001.100110011100 → 10進数の -2257.6005859375 に相当

※SQL Server の内部的には、おそらく「c」のバイナリで格納されると思います。


一方、最大精度の float(53) が使われていたと仮定すると、
有効桁数 53bit なので、このあたりですね。
 (x) -100011010001.10011001100110011001100110011001100110010
 (y) -100011010001.10011001100110011001100110011001100110011
 (z) -100011010001.10011001100110011001100110011001100110100

上記の 2 進小数を 10 進小数に直してみると、こうなります。

 (X) -2257.5999999999994543031789362430572509765625
 (Y) -2257.59999999999990905052982270717620849609375
 (Z) -2257.600000000000363797880709171295166015625


今回の「-2257.5999999999999」も「-2257.6」も、
もっとも近い値は Y の値ですから、
実際は両値とも、同じバイナリであると言えるでしょう。


=== 以下蛇足 ===

上記だけ見ると、X と Y は 17 桁ぐらいの精度をもっているかのようにも
見えますが、それはたまたたま、そういう数値域にあったというだけです。

内部的には、最大でも「53 bit 分」の有効桁数しかありません。

「53 bit」で表せる値の範囲は、符号無し10進整数で「0〜9007199254740991」の
範囲です。すなわち約 15.9 桁が、最大精度ということですね。

この15桁(53bit)の数値列に対し、何桁目に小数点を打つのかという形で
値を管理しているのが、『浮動小数点型』である float(53)型 です。

=== 蛇足ここまで ===


もしも、10 進数表記での誤差を抑える必要があるのなら、float ではなく、
『固定小数点型』である decimal 型を使ってみてください。
これならば誤差が出る心配はありません。

元データが float 型である以上、今更型を変更してみたところで、
既存のデータの誤差を解消できるわけではありませんが、
今後の事を考えれば、データ型を見直すことも必要かと。
引用返信 編集キー/
■75339 / inTopicNo.4)  Re[3]: SQLServer2000→2008R2 へのデータ以降
□投稿者/ ハルハル (12回)-(2015/03/17(Tue) 10:18:44)
No75338 (魔界の仮面弁士 さん) に返信

回答ありがとうございます!
float型の仕様を思い込みで勘違いしていました…

SQLServer2000で作成した時点で、float型を使用した経緯全く読めませんが、
DB定義を変えられるようであれば、decimal型に移行してみたいと思います。

丁寧な解説までして頂き、重ねてありがとうございます。


解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -