
Windowsの標準電卓で4の平方根が2でなかった仕様、変更される 81
ストーリー by hylom
どうやって修正したのだろう 部門より
どうやって修正したのだろう 部門より
Windows 10の電卓アプリで、「4の平方根が2にならない」不具合が修正されたとのこと(PC Watch)。
これは電卓アプリが内部的に32桁精度の浮動小数点演算で計算を行っているためで、4の平方根(√4)を計算すると表示上は2に見えるが、内部的には「1.99999999999999999989317180305609」という値になっており、この結果を使ってそのまま計算すると不具合が発生することがある。たとえば「√4-2」が「-1.068281969439142e-19」になってしまうそうだ。
当初Microsoftはこの挙動を仕様としていたが、このたびこの問題を修正するアップデートが配信されたそうで、これによって4の平方根は2になるという。
計算機イプシロンとその周辺 (スコア:3, 興味深い)
一般の電卓はどういうアルゴリズムになっているのだろう
電卓マニアさん、教えてください
(電卓でIEEE754使っているということはないよね?)
とか考えていたらやはり実装は色々みたい
http://verifiedby.me/adiary/097 [verifiedby.me]
Re: (スコア:0)
アプリではない普通の電卓は基本的にはBCDの浮動小数です。
極少数binaryの電卓もありましたが、ほとんどはBCDです。
例えばCasioやSHARPの関数電卓は内部的にはguard digit込みで15桁の精度があります。(表示は12桁)
Re: (スコア:0)
すいません勘違いしていました。端数処理や桁落ち時の処理の話でしたね。
仰る通り、この辺りは各社様々です。
桁落ちの他にもπ/n rad付近の三角関数やべき乗の扱い方等メーカー毎に違いがでてきます。
HPのように敢えて何もしないメーカーもあります。(だからsin(π)が0にならなかったりしますが設計思想の違いですね。)
誤差の理由と思われるもの (スコア:2)
「1.99999999999999999989317180305609」という数字全体の精度は(先頭の1を除けば)32桁なのに、9が連続している部分が18桁ぐらいしかないのがポイント。
計算機アプリの内部数値表現は32桁精度なのに、ルートの計算だけは拡張倍精度浮動小数点数(80ビット、仮数部の精度が約19桁)で行われてると推測される。
.NET Frameworkだと誤差は出ない (スコア:1)
.NET Frameworkにはそもそも単精度実数向けのSqrt()関数がないっぽいので、そのためかもしれない。
電卓も倍精度で計算するように直せばいいのでは。
PS> ([math]::sqrt(4)-2).tostring("e20")
0.00000000000000000000e+000
PS> ([math]::sqrt(0.04)-0.2).tostring("e20")
0.00000000000000000000e+000
0.1は想定通り誤差が出る。
PS> (0.1).tostring("e20")
1.00000000000000010000e-001
Re:.NET Frameworkだと誤差は出ない (スコア:1)
普通はお金の計算で平方根がでてくるの?
平方根くらいならともかく
10進小数で超越関数のアルゴリズム組むくらいなら
2進小数に一度変換するのが「普通」の考え方だと思う
よくあるよくある (スコア:0)
Win7の電卓でも再現出来たし……?
Re: (スコア:0)
XPの電卓でも再現しますが挙動が違うようです。
XPの電卓:
-8.1648465955514287168521180122928e-39
7の電卓:
-1.068281969439142e-19
10の電卓(?):
-1.068281969439142e-19
XPの方が精度高いんかな。
計算結果から進数変換したいときとか7のでも大分イライラするからXP(XP Modeから回収)の電卓動かしたほうが便利なんじゃないかと思ってしまう。
ていうか#3389277 [srad.jp]のリンク先でも言及されてるような過桁落ちされると電卓としては困ったことになる気が。
Excelの過桁落ちだって結構色々と批判されてるっていうのに(発生条件がゆるすぎるせいかもだが)……
Re:よくあるよくある (スコア:2)
Windows 7 で確認しましたが、ふつうの電卓モードと関数電卓モードでは精度が異なります。
普通の電卓 -1.068281969439142e-19
関数電卓 -8.1648465955514287168521180122928e-39
プログラマは√を知らないようでボタンが押せません
Re:よくあるよくある (スコア:3)
プログラマが知らないのは、平方根ではなく、小数。
というか、あのモードは、プログラマというより、基数設定付き整数だよね。
どこまで修正されたのかな? (スコア:0)
「√16-4」とかどうなるんだろう
#私が昔計算系のアプリ作ったときはほとんどの部分を素因数分解で処理したなぁ
Re: (スコア:0)
「√16-4」とかどうなるんだろう
0になりました。
Re:どこまで修正されたのかな? (スコア:1)
√(0.04)-0.2 はダメでした。
Re: (スコア:0)
0.04, 0.02 の時点で正確に表せていない。
Re: どうやって修正したのだろう (スコア:0)
アドホックに修正
https://twitter.com/ockeghem/status/982136647251718148 [twitter.com]
Re: どうやって修正したのだろう (スコア:1)
修正完了、コミット…と
if (x == 4.0) return 2.0;
else if (x == 0.04) return 0.2;
else return sqrt(x);
Re: どうやって修正したのだろう (スコア:1)
元記事に、完全平方(perfect square)の場合を検出して正確な平方根を返すようにしたとちゃんと書いてるんだが、誰も読んでないのか。hylomが読んでいないのは当然としても。
修正方法が分かれば、隣のツリーで盛り上がっているような小数の場合が修正されていないことも完全平方の定義からまったく不思議はないとわかる。
Re: (スコア:0)
それをアドホックというのはおかしい。
そもそも整数と小数は分けて考えないといけない。
十進数の0.04自体を二進数で正確にあらわせないし。
整数の平方根は無理数になるか整数になるかどちらかなので、
今回のやつはそれを真面目に判定するようになっただけのこと。
https://ja.wikipedia.org/wiki/%E5%B9%B3%E6%96%B9%E6%95%B0 [wikipedia.org]
Re: (スコア:0)
√0.0625-0.25もダメなので、正直かなり精度が低いのは確か。
PC Watch記事中の「32桁精度の浮動少数計算」って、まさか単精度実数のことじゃないよね?
Re: (スコア:0)
> 十進数の0.04自体を二進数で正確にあらわせないし。
浮動小数点では正確に表せないというなら同意しますけど、単なる分数なんだから二進数であらわせないまで言うと言い過ぎでしょ。分子と分母を値として保持すればいいんだから。
「32桁精度の浮動小数点演算」は誤訳 (スコア:0)
単精度,いわゆる float のことを言ってるんだろうけど
floatはデータサイズが32bits(つまり2進数で32桁)なだけで
32桁精度ではありません.
英文を誤訳してると思います.
Re:「32桁精度の浮動小数点演算」は誤訳 (スコア:2, 興味深い)
> 単精度,いわゆる float のことを言ってるんだろうけど
言ってないですよ。MSのリリースによると、電卓では四則演算と整数のべき乗以外の演算は"an extended precision library that produces 32 digits of precision"が使われているということなので、誤訳じゃないと思います。
# そもそもfloatの精度じゃ1.99999999999999999989317180305609なんて値は表現できない
Re: (スコア:0)
先頭の"1."を除けばちょうど32桁ですな。精度が高すぎるために誤差が可視化されてしまった(doubleなら丸められてた)可能性が?
Re: (スコア:0)
自己レス。やはりdoubleだと丸められますね。
PS> [double]::Parse("1.99999999999999999989317180305609")
2
doubleの10進数の精度は約16桁なので、有効桁数が2倍ということは、128-bit floating numberを使ってそうです。
Re:「32桁精度の浮動小数点演算」は誤訳 (スコア:1)
自己レス。やはりdoubleだと丸められますね。
PS> [double]::Parse("1.99999999999999999989317180305609")
2
doubleの10進数の精度は約16桁なので、有効桁数が2倍ということは、128-bit floating numberを使ってそうです。
違います。Windows98からは任意精度演算ライブラリを使っています。
https://blogs.msdn.microsoft.com/oldnewthing/20040525-00/?p=39193 [microsoft.com]
Re:「32桁精度の浮動小数点演算」は誤訳 (スコア:1)
そのページにも、任意精度なのは四則演算だけで平方根などは32桁精度(32 digits of precision)で行われるって書いてますよ。
> Today, Calc's internal computations are done with infinite precision for basic operations (addition, subtraction, multiplication, division) and 32 digits of precision for advanced operations (square root, transcendental operators).
Re:「32桁精度の浮動小数点演算」は誤訳 (スコア:1)
任意精度演算って必ずinfinite precisionである必要はないです。
必要に応じて桁数を可変できるのが任意精度です。
(あと任意精度演算の~桁精度というのはbinary64やbinary128等2進数浮動小数の~桁精度相当というものとは別です。)
現実には無限に桁を増やすのは得策ではない等の事情で桁数を制限して使っています。
下の方に同じ任意精度演算ライブラリを用いたPower Calculator PowerToyは512桁精度って書いてありますね。
Re: (スコア:0)
違うよ。それは四則演算とべき乗だけ。
https://blogs.msdn.microsoft.com/oldnewthing/20160628-00/?p=93765 [microsoft.com]
Specifically, it uses an arbitrary precision arithmetic library for rational operations: addition, subtraction, multiplication, division, and raising to a positive integer power. Other operations use an extended precision library that produces 32 digits of precision.
"extended precision"という用語は一般に浮動小数点数に使う用語(Wikipedia [wikipedia.org])だし、有効
Re: (スコア:0)
なんでdouble使わないんだろう?
floatじゃないと速度が出なくて困るようなアプリケーションでもあるまいに。
Re:「32桁精度の浮動小数点演算」は誤訳 (スコア:1)
電卓ならBCDなりDPDなりの10進使えよ
関数電卓ならdoubleでもいいけど
浮動をやめよう (スコア:0)
結局のところは浮動小数の精度がどんなに上がっても解決しない問題かもしれません
計算速度低下は止むを得ないですが
新たな選択肢として固定小数decimal(numeric)で計算できる様に成って欲しいものです
Re: (スコア:0)
WIndows98以降の電卓は任意精度演算ライブラリを使っていまして、
ちゃんと32桁精度があります。
https://blogs.msdn.microsoft.com/oldnewthing/20040525-00/?p=39193 [microsoft.com]
どうしてるんでしょうか? (スコア:0)
対数とって、2で割り、真数に戻してるんでしょうか?
#昔は手計算でルートを開かせられたんだ…
#私は覚えていないです。だって電卓あったし…
Re:どうしてるんでしょうか? (スコア:2, 参考になる)
今回の修正前の挙動については、以下のページに書かれてますね。
https://blogs.msdn.microsoft.com/oldnewthing/20160628-00/?p=93765 [microsoft.com]
> 対数とって、2で割り、真数に戻してるんでしょうか?
それで合ってるようです。
Re: (スコア:0)
>exp(½ ln x)
それはそもそも精度的にあんまりよろしくないような…。
任意のべき乗根を出す計算ボタンならともかく、「√」のボタンなら
https://cpplover.blogspot.jp/2010/11/blog-post_20.html [blogspot.jp]
のようなアルゴリズムもあるし、
手計算でやった筆算アルゴリズムを使ってもよさそうだし…。
Re:バグなのに、仕様って… (スコア:2, 参考になる)
本件については、マイクロソフトを責める気にならない。計算機の挙動として納得できてしまうので。
しょせんはデジタル。アナログな数値を表現するには限界があるんだよねえ。
#利用者フレンドリーじゃないのは認めるけど・・・でも、高校で「近い数値同士を引く時は気をつけろ」って習ったよね?
Re: (スコア:0)
右に同じ.
1わる3かける3が「0.999999」になるようなもんだと思う。
数式を解析して誤差を最小にする仕組みの有無の問題だから、
安価な電卓だとこれが仕様になる.
#50ヘルツ専用の時計を60ヘルツの電源に繋ぐようなもんで。
Re: (スコア:0)
たかがWIndows電卓ソフトの計算にCPU速度が不足するはずないんだから、浮動小数点じゃなくちゃんと任意精度演算使えよ、というツッコミはなしなのだろうか。
Re:バグなのに、仕様って… (スコア:1)
たかがOSの付属appにそれだけの実装コストをかけるか?というツッコミをあなたにあげよう。
Re: (スコア:0)
はたして、任意精度で、1÷3や、√2×2の計算が有限な時間で終わるのだろうか
Re: (スコア:0)
それは任意精度と無限桁数を間違えてますね。上のほうにも任意精度の解説ありますが。
#しかもすでに使ってるという情報すら…
Re:バグなのに、仕様って… (スコア:2)
Javascriptで0.1+0.2を計算してみてから言えば?
無知は罪だ。
Re:バグなのに、仕様って… (スコア:1)
???「本当にその事象で困った人だけ石を投げなさい」
√4がキッチリ2だったら気持ち悪い (スコア:1)
Re: (スコア:0)
NVIDIAの2+2=4.1も忘れちゃいけないw
Re: (スコア:0)
√2とか計算させてもきっちり正確な値は表示されないじゃん。√4とかだけは、たまたま上手く行くべきだ、ってのが間違い。
Re: (スコア:0)
こいつ何も理解してないw
Re: (スコア:0)
そうは言っても一般人はIEEE754どころか浮動小数点数の存在すら知らないだろうしねぇ
説明が難しいよ
Re:計算結果=表示内容では無いって (スコア:1)
質問です。
>そして表示では四捨五入します。
本当に四捨五入ですか?
いや、JISの数値丸めで四捨五入が使えるようになったのが近年でして。
計算機で都合の良い丸め方などあるのでしょうか?
Re:計算結果=表示内容では無いって (スコア:1)
そうなんですね。
因みに高校で五捨五入と習いました。