はじめに
つい先ほど、Power Appsで小数の計算を行った際に例えば以下のように計算に誤差が生じてしまったので、簡単に原因と対策を纏めます。
発生した誤差の例)
10 + 0.1 = 10.099999999996
一応断っておくと、これは市民開発者向けに纏めた記事なので、情報系に明るい人からすると、今更そんなこと詳しく書かなくても。。。な内容になっています。
予めご了承ください。
問題の根本原因
このような小数の計算で誤差が生じる。という問題はPower Appsに限らず、他のプログラミング言語でも発生する問題です。
ではなぜ誤差が生じてしまうのか?というと、浮動小数点型の丸め誤差によってこの問題が発生します。
"浮動小数点型"とはプログラミングにおける変数のデータ型の1つで、実数を表すデータ型のことをいいます。
まず前提として、コンピュータ上では我々が普段の生活で扱っている10進数ではなく2進数で処理が行われています。
10進数は0~9の値で数値が表現され、9に1加算されると10に桁上がりが行われますね。
これは普段の生活でも利用している表現方法なのでなんとなくわかるかと思います。
2進数は、0と1の値で数値が表現されます。
10進数でいう'1'は2進数では'1'、10進数でいう'2'は2進数では'10'、10進数でいう'3'は2進数では'11'といったふうに表現されます。
なぜこのような表現方法を用いているのかというと、「コンピュータでの処理は0と1で表現されている」みたいな話はきいたことはないでしょうか?
コンピュータ上ではオフを意味する「0」とオンを意味する「1」をいくつも組み合わせることであらゆるデータを表現しているのです。
とりあえず今はコンピュータ上では2進数という0と1の組み合わせでデータが処理されているんだな。という理解で大丈夫です。
さて、この2進数ですが 小数点以下の数を正確に表現できない という問題があります。
10進数を2進数に変換する方法の詳細は割愛しますが、小数の変換の理論だけ言葉で説明すると、変換対象の小数点以下の値にひたすらに2を掛けていき、整数部分の数値を抜出ます。これを小数部が0になるまで繰り返します。
簡単に例を示すと、「0.25」という10進数の数値を2進数に変換してみます。
0.25 * 2 = 0.50
0.50 * 2 = 1.00
という計算結果から、整数部分を抜き出すと、「0」と「1」になりますね。
なので10進数の'0.25'は2進数で表すと'0.01'になる。というわけです。
このやりかたをもとに、例えば冒頭でも計算に用いていた「0.1」を2進数に変換してみましょう。
0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
...
と、このように計算結果が循環してしまいます。
これにより、正確に小数の値が表現できずに、近似値を使うことによって丸め誤差が発生してしまうわけですね。
この微妙な計算誤差の積み重ねは特に金融系のシステムでは命取りなので金融系のシステムに関わっている人は必ず意識してシステム開発をしましょう。
対応策
この問題はfloat型やdouble型などの浮動小数点型を利用しなければ発生しない問題なので、int型などの整数型で計算を行うようにすればいいです。
たとえば、最初の例であれば
10 + 0.1 → 100 + 1
のように整数で計算する方法ですね。
ただ、最終的に小数で扱いたいんだ。という場合がほとんどだと思いますのでそのような場合は有効桁で値の四捨五入を行うという回避方法があります。
例えば有効桁2桁が欲しいのであれば
Round(10 + 0.1, 2)
みたいに計算させます。
おわりに
多分情報系とか他プログラミングを経験していないで、この問題にあたると「なんだこれ!?」となるかな?と思ったので簡単に纏めてみました。
だいぶかみ砕いて説明したので気になった人は調べてみるともう少し詳しい記事とか見つかるかと思います。
最後に、ここで記載した回避方法はざっくりこれでできるよ。
というやり方で、場合によっては誤差が生じる恐れもあります。
その誤差が一切許せないような厳密な計算が必要なのであれば、それはローコード/ノーコード開発ではなくプロの開発者に最低限そこの数値の計算を行うAPI開発を依頼する。や、システム開発自体を依頼する。といったことをしたほうが良いと思います。