- PR -

四捨五入

投稿者投稿内容
raccoon
ベテラン
会議室デビュー日: 2002/12/18
投稿数: 58
投稿日時: 2003-07-29 20:39
ども。raccoonです。
いやぁ,四捨五入ひとつにもいろいろあって,勉強になります。
特にunibonさんが紹介してくれたのがスマートで気に入りました。
そこで,

x = 2367896
y = x + (x Mod 10000)
z = y - (y Mod 10000)

なんてどうでしょう?

# 出してから気が付いた。
# これでじゅうぶんでしたね。

x = 2367896
y = x + 5000
z = y - (y Mod 10000)


[ メッセージ編集済み 編集者: raccoon 編集日時 2003-07-29 20:48 ]
Izumi, Y.
ベテラン
会議室デビュー日: 2002/03/19
投稿数: 77
お住まい・勤務地: 東京
投稿日時: 2003-07-29 21:01
ここでは一万の位で四捨五入する話ですので
コード:
y = x + 50000

z = y - (y Mod 100000) // z = y - y % 100000; in C#



raccoon さんの前者の方法はなかなかおもしろいですね(計算としては無駄だけど)。


[ メッセージ編集済み 編集者: IZUMI Yusuke 編集日時 2003-07-29 21:04 ]
raccoon
ベテラン
会議室デビュー日: 2002/12/18
投稿数: 58
投稿日時: 2003-07-29 22:19
IZUMI Yusukeさん,コメントありがとうございます。

引用:

IZUMI Yusukeさんの書き込み (2003-07-29 21:01) より:
raccoon さんの前者の方法はなかなかおもしろいですね(計算としては無駄だけど)。



わたしも我ながらフシギなやり方しちゃったなぁ,と笑ってます。

「modした値をうまく使えないか?」という出発点で考えたことが原因のようです。
最初の考えにつかまって,そこからすぐに抜け出せないとは・・・。たぶん年のせいです。
# 技術者として曲がり角にきたんじゃないのか?大丈夫か?->オレ

わたしの後者の方法は,『5を足してから切り捨てる』ということで,
このスレの最初のほうにある,Jittaさんやxkimuraさんのやり方と
本質的には似たようなものですね。切り捨ての方法が違いますが。

その意味では,前者の方はたしかに異質で面白いといえますが・・・。
いやぁ,お恥ずかしい。# しかもいつのまにか「常連さん」になってるのに・・・
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2003-07-29 22:34
本題とは離れてしまいますが、誤差を出来るだけ避けるなら、
doubleよりもdecimal型の方が良いですね。
整数部とスケールファクタで成り立っているので、
浮動小数点数のdoubleみたいな誤差は出ないし。

Cとかだと馴染みが無い型なので、ついつい忘れてしまいます(笑)。
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2003-07-29 23:39
引用:

unibonさんの書き込み (2003-07-29 18:55) より:
引用:

yamasaさんの書き込み (2003-07-29 02:08) より:
引用:

Jittaさんの書き込み (2003-07-28 18:32) より:
 10万分の1にして、0.5足して、int型に代入し、10万倍する。FAQ「小数点x桁で四捨五入する」と、考え方は同じです。


そのやり方には大きな落とし穴があります。
計算に浮動小数点を使用していた場合、丸め誤差により
正しくない値になってしまうことがあります。


そのやり方に問題はないはずです。
反例(正しくない値になってしまうこと)はないと思います。

もちろん使う道具(double や float)が持つビット数の制限を
越えない範囲内で使うという前提はあります。


まあ、MyRoundの実装に限って言えば、
おっしゃる通り正しい結果が得られますね。
# value / 100000.0 の時点で小数部分に必要な情報は
# 0.5 を加えると繰り上がるかどうかだけなので、
# value そのものが浮動小数点型で正確に表現できていれば
# 誤差の影響は受けない。

ただし一般論としては、float や double 型で小数を扱う場合に
誤差の影響を注意深く考慮しなければならないことに変わりはありません。
引用:

C# (や VB.NET) の仕様では、整数を扱えるビット数の幅が、
float < int < double < long
なので、double を使うよりは long を使ったほうが、
扱える数値の範囲が広くて有利ですが、
それはたまたまそういうビット数に決まっているだけであり、
浮動小数点型の double だから理論的な誤差がある、というわけではないです。


それは確かにそうなんですが、たとえば Int32.MinValue 以上 Int32.MaxValue 以下の
整数を表現するには、int型が一番適していますよね。
引用:

もし long がなかったら double のほうが有利です
(有利・不利はあくまでも扱える数値の範囲だけであり、誤差の有無とは別です)。


数値型の内部表現をdouble型に統一してしまった言語もありますが、
そういうのはC#等の流儀には反しているでしょう。
MUSE
常連さん
会議室デビュー日: 2003/04/06
投稿数: 42
投稿日時: 2003-07-29 23:49
# 最初、スレッド一覧を見たとき、四捨五入が燃えてるので思わず笑ってしまいました。失敬。
# 大昔のBASICの時はあんまり考えずにやってたような記憶があります。懐かしい。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2003-07-30 00:04
引用:

LEDさんの書き込み (2003-07-29 23:49) より:
# 大昔のBASICの時はあんまり考えずにやってたような記憶があります。懐かしい。


大昔のBASICには10進浮動小数のものがあったりしたような。
この場合、有効桁数の問題はあっても誤差の問題は起こらなかったり。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-07-30 11:49
unibon です。こんにちわ。

引用:

yamasaさんの書き込み (2003-07-29 23:39) より:
ただし一般論としては、float や double 型で小数を扱う場合に
誤差の影響を注意深く考慮しなければならないことに変わりはありません。


一般論としては、そうだとうなずけます。

引用:

yamasaさんの書き込み (2003-07-29 23:39) より:
それは確かにそうなんですが、たとえば Int32.MinValue 以上 Int32.MaxValue 以下の
整数を表現するには、int型が一番適していますよね。


上記の「整数を表現」という言葉がどこまでを意味するのか分かりませんが、
もしも数値を変数に格納することならば、おっしゃるとおりです。

ただ、計算途中の値についてはその限りではないと思いますので、
以下に言及します。
あまり分かりやすい例ではないのですが、
四捨五入するやりかたとして、つぎの2つのやりかたを比較してみます。
#すみません、VBScript です。 適宜翻訳して読んでください。
コード:
Function MyRound(ByVal value)
    MyRound = CLng(Int(value / 100000.0 + 0.5) * 100000.0)
End Function

Function HeeRound(ByVal value)
    HeeRound = (value + 100000 / 2) - ((value + 100000 / 2) Mod 100000)
End Function


たまたま VBScript では64ビット整数型がないこともあり、
64ビット整数型も64ビット浮動小数点型も使わずに整数型だけで演算しようとすると、
32ビット整数型までしか使えません。
こうすると引数が 2147433648 以上だと
HeeRound の内部で演算途中にオーバフローが発生します。
こういう時にはビット数の多い64ビット浮動小数点型が使えるのならば
"浮動小数点型の特質を知った上で"使うのは構わないと思います。
MyRound のほうは、入力が 2147450000 以上のときに
関数の戻り値がオーバフローすることはあります(これは四捨五入の定義上仕方がない)が、
演算途中でのオーバフローはありません。
#四捨五入の例だと、2147433648 以上のことなんて軽微なのであまり重要性はないかもしれませんが、
#他の変換だとたとえば上限が1桁少なくて 214748364(= 2147483648 / 10)以上が使えないとか、
#そう場面もチョクチョクありうると思います(うまい例が見つかりませんが)。

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

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