1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

jq 1.7の新機能ー数値精度

Last updated at Posted at 2024-03-04

JSON処理のコマンドラインツールであるjqが、5年ぶりにアップデートしました。現在の最新は1.7.1(2023年12月リリース)です。1.6からいろいろと改定や新機能の追加があって、ますます楽しくなっています。

全容はGithub上のリリースノートを見ていただくとして、今日は改良された数値精度を試してみます。

これまでは

jqは、IEEE 754の倍精度形式(binary64)で数値を表現します。この仕様では、仮数部(A × 10BのAの部分)は10進数でだいたい16桁くらいまで、指数部(Bの部分)は308くらいまで正確に表現できます。それ以上では、丸め誤差が発生します。

たとえば、次で用いている円周率のπは小数点以下が20桁で定義されていますが(Cのmath.hから取ってきました)、バージョン1.6では切り捨てられてしまいます。

$ jq-1.6 --version
jq-1.6                                      # バージョン1.6を使っています

$ echo 3.14159265358979323846 | jq-1.6 '.'
3.141592653589793                           # 切り捨て

蛇足ですが、数値の桁数を調べるには、あらかじめ(jqに入力する前に)文字列化して、lengthです。

$ echo '"3.14159265358979323846"' | jq-1.6 'length'
22                                          # 先頭の値とドットを含めて22桁なので、小数点以下は20桁

-nオプション(ロングフォーマットは--null-input)を使ってフィルタ内に記述するのは✕です。その時点でIEEE 754表現に変換されてしまうからです。

$ jq-1.6 -n '3.14159265358979323846 | tostring | length'
17                                          # お前はすでに切り捨てられている

JavaScriptでは

JavaScriptでも事情は同じです。数値はIEEE 754倍精度で表現されるので、一定以上の精度の値は丸められます。

Node.jsで試してみます。

$ node
Welcome to Node.js v20.9.0.
Type ".help" for more information.
> JSON.parse(3.14159265358979323846)
3.141592653589793

これからは

数値の桁数は、読み込まれた時点ではその精度が保たれてるようになりました。

$ jq --version
jq-1.7.1                                    # 1.7です

$ echo 3.14159265358979323846 | jq '.'
3.14159265358979323846                      # 精度が保存されます

なので、-nでフィルタ内に記述することもできます。

$ jq -n '3.14159265358979323846 | tostring | length'
22                                          # 今度はあってる

<>などの比較演算もできます。小数点数以下20桁のπとその末尾を1つ増やした値を比較してみます。

#                              V                       V が1つ違う
$ jq -n '[3.14159265358979323846, 3.14159265358979323847] | .[0] < .[1]'
true

1.6ではこうはいきません。

$ jq-1.6 -n '[3.14159265358979323846, 3.14159265358979323847] | .[0] < .[1]'
false

比較演算はできますが、普通の演算では1.6同様に桁落ちします。演算と同時にIEEE 754表現に変換されるからです。0を加えてみます。

$ jq -n '3.14159265358979323846 + 0'
3.141592653589793

おわりに

数字(文字)をずらずら書き連ねるだけで数値を表現できるJSONでは、数値の精度に制約はありません。しかし、その処理系ではIEEE 754など表現形式の精度に依存します。そのため、JSON仕様のRFC 8259は極端に大きい、あるいは精度の高い数値を使うときは、相互運用性に気をつけるように注意を促しています。

比較ができるようになったからといって、大きな数値を使うのは考えものなのは、これまでと変わりません。

1.7では、他にも、細かいところで性能向上も図られています。まだ1.6をお使いなら、これを機会に1.7にアップグレードしましょう。

参考

表紙 表紙

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?