- PR -

四捨五入

投稿者投稿内容
MUSE
常連さん
会議室デビュー日: 2003/04/06
投稿数: 42
投稿日時: 2003-07-30 21:39
引用:

なちゃさんの書き込み (2003-07-30 00:04) より:

大昔のBASICには10進浮動小数のものがあったりしたような。
この場合、有効桁数の問題はあっても誤差の問題は起こらなかったり。


そうですね〜。昔の言語は、おおらかだった・・・。大体、あってればいいやみたいな。
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2003-07-31 00:19
引用:

unibonさんの書き込み (2003-07-30 11:49) より:
たまたま VBScript では64ビット整数型がないこともあり、
64ビット整数型も64ビット浮動小数点型も使わずに整数型だけで演算しようとすると、
32ビット整数型までしか使えません。
こうすると引数が 2147433648 以上だと
HeeRound の内部で演算途中にオーバフローが発生します。
こういう時にはビット数の多い64ビット浮動小数点型が使えるのならば
"浮動小数点型の特質を知った上で"使うのは構わないと思います。


ええ、64ビット浮動小数点型は32ビット整数型より広い範囲の整数
正確に表現できますから、
64ビット整数型が存在しない言語で大きな整数を扱う必要がある場合に
64ビット浮動小数点型を代替として使用することに異論はありません。

しかし、その場合でも小数演算はできる限り避けるべきです。
たとえば以下のコードでは整数演算のみで四捨五入を計算できています。
コード:
static int MyRound(int value) {
  if (value < 0)
    throw new ArgumentOutOfRangeException();
  double tmp = (double)value + 50000;
  tmp -= tmp % 100000;
  if (tmp > Int32.MaxValue)
    throw new OverflowException();
  return (int)tmp;
}


# もちろん、上の例はC#のものなので、double -> long にしたほうが良いですが。
引用:

ただ、上記で書いた「浮動小数点型の特質を知った上で」という前提が、
結構難しいんですよね。これは否定できません。
多くのかたのご指摘もこれを危惧されてのことだろうと推測します。
ただ、こういう問題はプログラミングのロジックの話というよりは、
プログラミング標準やプロジェクト管理とかそっちの方で語るもののような気もします。


C#やVB.NETならdecimal型があるので、
とりあえずfloat, double型は原則禁止にしておいても
あまり不都合はないですね。
ぢゃん♪
大ベテラン
会議室デビュー日: 2003/06/12
投稿数: 208
お住まい・勤務地: 都内
投稿日時: 2003-07-31 08:28
引用:

LEDさんの書き込み (2003-07-30 21:39) より:

そうですね〜。昔の言語は、おおらかだった・・・。大体、あってればいいやみたいな。


……違います。

引用:

なちゃさんの書き込み (2003-07-30 00:04) より:

大昔のBASICには10進浮動小数のものがあったりしたような。
この場合、有効桁数の問題はあっても誤差の問題は起こらなかったり。


というのは、10進数を10進数として格納するから、有効桁数を超えない範囲では誤差が出ないという意味です。
それに対し、10進数を2進数として格納する場合、2のn乗およびそれの組み合わせで表せる範囲は誤差が出ないのですが、そうでないと簡単に誤差が出ます。

たとえば、10進数ではきりのいい 0.1 なんてどうでしょう。
これを2進数に変換すると循環小数になってしまい、10進数の0.1を誤差なく格納することはできません(指数部が10進数なら別ですが)。ただし近似値にはなります。
ちょっと計算が面倒くさかったので どこかから拾ってきた数字ですが、
0.1[10進]→0.00011001100110011001100……[2進]
となるようです。

10進数を10進数として格納する場合、たとえば有効桁数が3桁でも、0.1をそのまま0.1として格納します。

で、これだけなら良いように見えますが、欠点も大きいです。私の記憶では、だいたい次の欠点がありました。

  • 有効桁数を超えると、途端に誤差が大きくなります。2進数格納のような近似値ですらありません(有効桁数を超えたところで切り上げ/切り捨て/四捨五入が発生するでしょう)。
  • 格納効率が良くないです(メモリを1桁当たり16分の10、つまり5/8しか使いません)。
  • 計算速度も2進数格納方式より不利です。



[ メッセージ編集済み 編集者: ぢゃん♪ 編集日時 2003-07-31 08:33 ]
Izumi, Y.
ベテラン
会議室デビュー日: 2002/03/19
投稿数: 77
お住まい・勤務地: 東京
投稿日時: 2003-07-31 11:53
引用:

yamasaさんの書き込み (2003-07-31 00:19) より:
コード:
//(前略)
  double tmp = (double)value + 50000;
  tmp -= tmp % 100000;
//(後略)




% 演算は double 型には適用できなかったような…
tmp = Math.Floor(tmp / 100000) * 100000; かな?
#100000 で割っても整数部には誤差がでないはずです(有効桁数の範囲内なら)。

引用:

LEDさんの書き込み (2003-07-30 21:39) より:
そうですね〜。昔の言語は、おおらかだった・・・。大体、あってればいいやみたいな。


おおらかだったのは言語ではなくてユーザーですね。確かに BASIC が流行っていた頃は誤差なんて気にする人はほとんどいなかったように思えます。
#でも、研究で FORTRAN とかを使っていた人は昔から誤差に敏感だったかも。
MUSE
常連さん
会議室デビュー日: 2003/04/06
投稿数: 42
投稿日時: 2003-07-31 12:27
[quote]
ぢゃん♪さんの書き込み (2003-07-31 08:28) より:

……違います。
[quote]
失礼!。あんまり本気にしないで〜。
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2003-07-31 14:26
引用:

IZUMI Yusukeさんの書き込み (2003-07-31 11:53) より:
% 演算は double 型には適用できなかったような…


C#では double 型にも % 演算がありますよ。
http://www.microsoft.com/japan/msdn/library/ja/csspec/html/vclrfcsharpspec_7_7_3.asp
ですから、上のコードはちゃんとコンパイルでき、意図したとおりに動作します。
Izumi, Y.
ベテラン
会議室デビュー日: 2002/03/19
投稿数: 77
お住まい・勤務地: 東京
投稿日時: 2003-07-31 15:59
引用:

yamasaさんの書き込み (2003-07-31 14:26) より:
引用:

IZUMI Yusukeさんの書き込み (2003-07-31 11:53) より:
% 演算は double 型には適用できなかったような…


C#では double 型にも % 演算がありますよ。
http://www.microsoft.com/japan/msdn/library/ja/csspec/html/vclrfcsharpspec_7_7_3.asp
ですから、上のコードはちゃんとコンパイルでき、意図したとおりに動作します。


うわ、ほんとだ。これは失礼しました。
#実数型に剰余演算子がある言語は少ないので、思いこみで書いてしまいました。

スキルアップ/キャリアアップ(JOB@IT)