前提・実現したいこと
.999...の値を1として処理したい
発生している問題・エラーメッセージ
現在小数点許容、基本的に切り捨て処理である処理を作成しています。
(Decimal型で受けて、Decimal型で返します)
このとき、例えば123.9999....の値の場合、返り値が123になってしまいますが、
実計算上では124になってほしいのです。
この対策についていろいろと調べてみましたが、いまいち要領を得ず
(.999...は浮動小数点としての計算的には正しい処理なので当然なのでしょうが...)
このままだとif条件分岐などで対応してしまいそうなので、
0.999... = 1 にする一般的で最適な方法について、
ぜひ皆様のお知恵を拝借させてください。
該当のソースコード
private decimal Kirisute(decimal d){ //処理 } decimal da = 1 decimal db = (da / 3) decimal dc = db * 3 decimal dd = Kirisute(dc) // expected: dd = 1, dc = 0.999... // actual: dd = 0.999..., dd = 0.999....
補足情報(FW/ツールのバージョンなど)
C# 3.0
VB 2008
>切り捨て処理
0.999→1なら「切り上げ」だと思いますが、なぜ「切り捨て」と?
基本的に0.5, 0.91などは切り捨て処理を行うが、
例外的に0.999...は切り上げ処理にしたい...という目的の関数であるためです。
具体的に記載しておいてください。
すでに2つ、その要件が満たされない回答がついてしまっていて無駄になっています。
意味不明ですね。
0.99 は 1 になり、0.998 は 0 になるのなら、1 < 0 となってしまいます。
0.001を足すという方法がBAに選ばれてますし,
結局,本当にやりたいことは「9が連続する場合だけを特別扱い」ではなかった,ということかな?
>Zuishinさん
0.990と0.998(桁そろえしてます)、さらに0.999があるとして、当然1 > 0.999 > 0.998 > 0.990です。
桁そろえのために足す0.0..1の桁数は可変ではなく固定なので、0.001を足すと、1.001 > 1.000 > 0.999 > 0.991 で、小数点以下丸ごと切り捨てなので、1(1)、1(0.999)、0(0.998)、0(0.99)という結果になります。よって0.990 = 0であって、 0.998 = 0です。
この質問のなかにある`.999...`とは、小数点以下において9が無限に続くことを意味しており、小数点以下の9の数が3ケタとか4ケタとかに決まっているわけではありません。また、0.99は確かに小数点以下に存在する数字すべてが9になっていますが、0.99の実態というのはその9以下は0で表現されているところが省略され0.990000...といったものであるため、これは意図したい無限小数ではありません。
この質問と、そしてBAに至るまでに、私自身が無限小数を1とみなす処理は現実的にできず、有効桁数を設定する必要があると考えを変えたので、質問とBAの意味するところの差異に混乱があったかもしれません。
>fanaさん
まず前提として、たとえば0.99899という数字があって、足す桁数をそろえ、0.00001を足すとします。
すると0.99900になりますが、正の位まで繰り上がってないので、小数点以下を切り捨て、結果は0となります。
おっしゃりたいのは、0.9992という数字があったとき、加える小数点の位を0.001と定義してしまうと、すべての小数点以下が9ではないにも関わらず1になってしまう、ということですよね。
もちろんできることであれば0.999....という場合のみに1という扱いにしたかったのですが、
皆様からご回答をいただく中で、有効桁数を決めない限りそのような処理は不可能である
(もちろん数値を文字列に変換し、ループを回してすべての小数点以下の文字が9であるかどうか、という判断を行う方法を取れば可能ですが)という
考えに至りましたので、最も無難で処理も煩雑にならない、有効桁数を定義する処理をBAにさせていただいた次第です。
質問に書いてあるのは「9 が無限に連続した時」というもので、「9 が〇〇個連続した時」というものではありません。無限は扱えないので途中で切る必要があります。どこで切るかが示されていないので 9 の連続が途切れた時、もしくは数値が一定の上限を超えたときと推測されます。
つまり二通りの考え方があるわけですね。
「ここまでは質問者もわかった上で質問している」という前提で考えると意味不明になりますし、「ここがわかっていない」と考えると、どちらかあるいは両方を答える回答になります。
なので、次回質問された場合は、追記修正依頼を読んでそれに答え、質問意図を明確にしてください。でなければ回答者は推測で答えるより他なくなります。今回は二通りしかないので、たまたま推測が当たっているようですが、次回もそうなるとは限りません。「意味不明」と言われている時には、質問をした人が意味を明確にする必要があると思います。
だから私は回答していないし、他にも回答を控えた人が大勢いることでしょう。「今回は」回答した人の中から正解が出ました。
> (もちろん数値を文字列に変換し、ループを回してすべての小数点以下の文字が9であるかどうか、という判断を行う方法を取れば可能ですが)
これだと私の(問題の内容を間違った)回答と同じ結果になりそうな…?
>fanaさん
ほんとだ。そうなってしまいますね。
気づきませんでした。ありがとうございます。

回答5件
あなたの回答
tips
プレビュー







