gihyo.jp » DEVELOPER STAGE » 連載 » BK通信 ―Bad Knowhow Tsushin― » #02 数字のバッドノウハウ

BK通信 ―Bad Knowhow Tsushin―

#02 数字のバッドノウハウ

ソフトウェアなどを使いこなすために,ストレスを感じながらもしぶしぶ覚えなければならないようなノウハウ,「バッドノウハウ」(BadKhowhow)がテーマの本連載,第2回の今回は数値に関するバッドノウハウ(以下BK)を取り上げたいと思います。

JavaScriptのparseInt関数

JavaScriptには,文字列を整数に変換する組み込みの関数parseIntがあります。この関数は,第1引数に文字列,第2引数に基数を渡して使うのが基本です。しかし,基数を省略した場合は,文字列の中身に応じて自動的に基数が選ばれます。

その結果,"08"が8進数として解釈されて0(ゼロ)になる(8は8進数では無効な値),という厄介な挙動が発生します(リスト1)。

リスト1 JavaScriptのparseInt関数

// Firefox 2,IE 7ともに0が表示される
alert(parseInt("08"));

この挙動は,2桁の数字で入力された月や日を処理するプログラ ムでよく問題になります。「JavaScript parseInt」で検索すると" 08"が8進数として解釈されてはまった,というページが多数見つか ります。典型的な落とし穴です。

ECMAスクリプトの仕様書 を読むと,parseInt関数は基数が与えられず(または基数が0), 文字列の先頭が0xまたは0Xの場合は,文字列を16進数として解釈す ると明記されています。しかし,文字列の先頭が0の場合の解釈は 実装依存であり,8進数として解釈してもかまわないが,10進数と して解釈するのが望ましいと書かれています。

このような ちょっとした「賢い」挙動が思わぬ落とし穴を生む,というのはよ くあるパターンです。ソフトウェアを設計する上で,気をつけなけ ればならない点だと思います。

「このparseIntの挙動,何か似たようなものがあったような」と思っていたところ,C言語のstrtol関数が似たような仕様(文字列の先頭で基数が変わる)であることを思い出しました。parseInt()の祖先はこいつかもしれません。

printfの%g

先日,ちょっとした統計を集計するスクリプトを書いて実行したところ,予想外の結果が出て驚きました。たとえていえば,人口の最も多い都道府県は鳥取県(注1)という結果が得られたような感じです。

考えられる可能性としては,図1のようなものがあります。

図1 考えられる可能性

  • ① 予想外の結果だが実は正しい
  • ② 集計するスクリプトにバグがある
  • ③ 集計する前の段階でデータが間違っている

まず②を疑ってみましたが,単純に整数を足し合わせているだけのプログラムなのでバグがあるようには見えません。次に③の可能性を探ってみると,元のデータはprintf%gというフォーマットで出力されていることがわかりました。

%gは浮動小数点の数値のフォーマットに用いられます。同じく浮動小数点に用いられる%fと違い,%gは図2のような賢い動作をします。というわけで,筆者が整数だと思って足し合わせていた数値は実は浮動小数点だったのでした。たまたま筆者がサンプルとして見ていた数字が[1]の仕様によって整数のように見えていたため,データは整数だと思い込んでしまったのが敗因です。

図2 %gの動作

  • [1] 小数点以下に0が続く場合は省略する
    例:123.00 -> 123
  • [2] 数値がある程度以上大きい場合は,科学表記を用いる
    例:1000000 -> 1e+06

集計スクリプトの中ではRubyのto_iメソッドを使って文字列を整数に変換していたため,科学表記の数値がくると「e」の前の数字だけが整数として解釈されていました。「1e+06」が1000000ではなく1としてカウントされてしまうのですから,結果が予想とまったく異なっていたのは当然です。to_iの代わりにto_fを使って解決しました。

ちなみに,Rubyのto_iは基数が省略された場合は,文字列を10進数として解釈します。文字列の中身に応じて16進数や8進数として解釈するといったことはありません。

注1)
本槁執筆時点(2008年3月)で,日本で人口が最も少ない都道府県。
URL:http://www.stat.go.jp/data/kokusei/2005/youkei/index.htm

x86の浮動小数点演算

先日,あるプログラムをMac OS X(v10.5,Leopard)のgccでビルドして実行したところ,同じプログラムをLinuxのgccでビルドしたときと結果が微妙に異なることに気づきました。

結果を見ると,どうも浮動小数点演算の挙動が微妙に異なっているようです。原因としてまず思い当たったのは,x86の浮動小数点演算命令です。Intelのx86の浮動小数点演算は80ビットレジスタを使うため,他のプロセッサと結果が微妙に異なることがある,ということが知られています(注2)。

しかし,今回の場合,どちらもハードウェアはIntelのx86系のプロセッサを積んでいます。なのになぜ結果が違うのかと思って調べてみると,Mac OS X Leopardのgccはデフォルトで浮動小数点演算にSSE命令注3)を使っていることがわかりました。SSE命令を使った場合,x86伝統の80ビットレジスタは用いられないため,80ビットレジスタに起因する問題は起きません。

このときは結局,Linuxでビルドしたバイナリと同じ結果が欲しかったのでコンパイラオプションに-mno-sse(SSE命令を禁止)を追加してごまかしました。

以前にも別の場面でx86の浮動小数点演算の挙動ではまって,ブログに書いたことがあります(注4)。x86の浮動小数点演算の挙動はなかなか厄介な問題です。

注2)
『Binary Hacks』(高林 哲/鵜飼 文敏/佐藤 祐介/浜地 慎一郎/首藤 一幸著,オライリージャパン,2006)の「Hack #98:x86が持つ浮動小数点演算命令の特殊性」(p.366)に詳しい説明があります。
注3)
Intelが開発した高速な浮動小数点演算のための命令セット。SSEはStreaming SIMD Extensionsの略。
注4)
浮動小数点演算ではまった話」(bkブログ)。

まとめ

今回は数値に関するBKを3つ紹介しました。最初のparseIntのものは,わかってしまえば「なんだ8進数かよ!」で済む簡単な問題ですが,最後のx86の浮動小数点演算の問題は,なぜ結果が異なるのか理解するのはなかなか難しい,厄介な問題です。BKと一言で片付けるにはもったいない奥が深いテーマといえそうです。

著者プロフィール

高林哲(たかばやしさとる)

ソフトウェアエンジニア。バッドノウハウの研究,スルー力の探究,自転車置場の建設,Binary 2.0の布教などの活動を行っている。共著に『Binary Hacks』(オライリー 2006年)。ブログはhttp://0xcc.net/

著書

  • Binary Hacks ハッカー秘伝のテクニック100選

    Binary Hacks ハッカー秘伝のテクニック100選(オライリー・ジャパン)

トラックバック

  • parseInt実験

    BK通信 ―Bad Knowhow Tsushin―:#02 数字のバッドノウハウ|gihyo.jp … 技術評論社より。
    8進数は未だ扱ってないのでAS3でも試してみたところ、
    parseInt("08") は 8 と出ました。

    Tracked : #1  うむるむ (2008/10/02, 17:39)

コメント

コメントの記入

パスサポ

多数の情報処理技術者試験対策書籍の発行実績を誇る技術評論社がお届けする,資格試験合格サイト「めざせ! 情報処理試験 パスサポ」が開設されました。

ピックアップ

サクセスストーリーに続く,快適サーバー運用管理のヒント!

データの増大,煩雑な管理,システムダウン,セキュリティなど,迫りくる課題からシステム管理者の負担を軽くするポイントを解説します。

gihyo.jp インフラエンジニア情報局

ネットワークやITにかかわるあらゆる業種で必要とされるインフラエンジニアに向けた技術情報や心構え,その魅力について多角的に紹介。

テストエンジニア ステーション

いま,ITに関わるあらゆる開発業務で注目されつつあるテスト系エンジニアをターゲットにしたコンテンツサイトを展開します。

一行クイックアンケート

gihyo.jpで取り上げてほしいネタは?

※検索はページ右上の検索ボックスをご利用ください。

その他の連載

2010年版SEO体得講座

本連載では,いまや企業サイトの戦略の1つとして欠かすことのできないSEOについて,最新トレンドからすぐに使えるTipsまでを紹介します。

小型Linuxサーバの最高峰 OpenBlockS 600活用指南

搭載メモリの増加,CPUクロックの向上など,あらゆる面が強化された期待の新モデルOpenBlockS 600。この記事ではOpenBlockS 600の紹介から,活用するためのさまざまなノウハウを紹介していきます。

はじめMath! Javaでコンピュータ数学

プログラミング言語入門者向けに,知っていると役立つ数学的トピックスを紹介します。簡単な演習問題と解説で,即活用できる知識を目指します。

教科書には載っていない ネットワークエンジニアの実践技術

ネットワークエンジニア,インフラエンジニアのトラブル対応には,時には「教科書通りにいかない」テクニックが必要となります。資格試験では得られないこうした実践的な技術について,実例を元に紹介します。

Googleケータイ,世に現る

2008年9月,Googleが中心となって開発されている「Android」を採用した携帯電話「T-Mobile G1」が発表されました。本連載ではT-Mobile G1を中心にGoogleケータイに迫ります。

モバゲーオープンプラットフォームに挑戦!――面白法人カヤック流モバゲーオープンプラットフォーム企画と開発のイロハ

2010年1月にリリースとなったモバゲーオープンプラットフォーム。その制作企業であるカヤックが,アイデアを企画に落とし込み,開発までのノウハウを紹介します。

プロトタイピングツールSketchFlowを用いた,Silverlightアプリ開発

SketchFlowプロトタイプ作成からアプリケーション開発までをExpression Blend 3を使って実践的に解説します。

Ubuntu Weekly Recipe

Ubuntuの強力なデスクトップ機能を活用するための,いろいろなレシピをお届けします。

連載一覧

gihyo.jp

  • DEVELOPER STAGE
  • ADMINISTRATOR STAGE
  • WEB+DESIGN STAGE
  • LIFESTYLE STAGE
  • SCIENCE STAGE
  • NEWS & REPORT

書籍案内

  • 新刊書籍
  • 書籍ジャンル一覧
  • 書籍シリーズ一覧
  • 新刊ピックアップ
  • ロングセラー
  • 電脳会議

定期刊行物一覧

  • Software Design
  • WEB+DB PRESS
  • Web Site Expert
  • 組込みプレス

最近のコメント