64ビット整数のオーバーフロー判定についてのメモ

こんにちは。

去年の暮れに素数をつないで落ちつくんだ〜簡単!素因数分解で「京」を目指せという iOS/Android アプリをリリースしたのですが、その際、64ビット整数 (long型) 同士の掛け算の結果がオーバーフローしているかどうかの判定をする必要がありました。

これが思ったより悩ましかったので、その時の調べたり試したことをまとめてみました。

オーバーフローとは?

Wikipedia によると以下のような現象のことです。

デジタルコンピュータにおいて、演算結果がレジスタの表せる範囲や記憶装置上の格納域に記録できる範囲を超えてしまう現象、またはその結果レジスタ等に格納される値を意味する。オーバーフローは、本来演算結果を格納する場所とは違う場所に格納される場合がある。「溢れ」とも言う。 (算術オーバーフロー – Wikipedia)

要は計算の結果が大きすぎて、エラーになってしまった状態です。ゲーム内の得点の計算などでこれが発生すると、せっかくの記録が台無しになってしまうので、大問題です。

以下では、このオーバーフローの防ぎ方を考えていきます。なお、ここでは符号つき整数の場合を考えます。

加算(+)の場合

整数 a と整数 b の足し算の結果(和)がオーバーフローしていないかの判定を考えます。ここで、正の64ビット整数の最大値を LONG_MAX とし、a も b も正の値だとします。

I. 処理系依存の方法

これはC言語として保証されていない(と思う)方法ですが、符号付き整数がオーバーフローしてその最大値 LONG_MAX (9223372036854775807) を1超えると、逆に最小値 LONG_MIN(-9223372036854775808)になってしまう処理系がほとんどです。それを利用して「加算の結果が負になったらオーバーフローだった」と判定します。実用的にはこれでいいんじゃないですかね。

うちでは動作する加算オーバーフロー判定

II. 正攻法

処理系に依存しない方法を考えます。
a と b の和が LONG_MAX を超えるには、少なくとも a か b のどちらか一方が LONG_MAX/2 以上である必要があるので、

(1) a と b どちらも LONG_MAX/2 未満の場合、オーバーフローはしない

(2) a のみが LONG_MAX/2 以上の場合、a – LONG_MAX/2 + b がLONG_MAX/2 以上の場合、オーバーフローする

     b のみが LONG_MAX/2 以上の場合、b – LONG_MAX/2 + a が LONG_MAX/2 以上の場合、オーバーフローする

(3) a と b どちらも LONG_MAX/2 以上の場合、オーバーフローする

LONG_MAX は実際には奇数ですので、計算の際はそれを意識してコードを書く必要があるかもしれません。

処理系にほとんど依存しない加算オーバーフロー判定

[2017.03.02 追記]
上記のような方法を取らざるを得ないと思っていたのですが、コメント欄にご指摘をいただきました。

確かに a < LONG_MAX – b の判定ならオーバーフローを起こさずに可能ですので、a + b がオーバーフローするかどうか計算前に検知することができます。今後はこの方法でやろうと思います。(^^;

III. ハードウェア情報を読み取る

そもそもC言語などの高級言語ではオーバーフローと呼ばれる現象は、機械語(アセンブリ言語)の世界では単なるキャリーフラグを伴った加算なので、キャリーフラグを読み取ればオーバーフローしたかどうか判定できます。しかしこの方法は完全な処理系依存になってしまうので、ここでは扱いません。

乗算(×)の場合

本記事を書こうと思ったきっかけになったケースです。整数 a と整数 b の掛け算の結果(積)がオーバーフローしたかどうかの判定を考えます。

I. 処理系依存の方法

上述の加算の場合、LONG_MAX を超えると負の値になりました。乗算の場合も、積が LONG_MAX を超えたら負の値になってくれるような期待をしていた時期が自分にもありました。
しかし実験の結果、

なんと、結果は正になったり負になったりで、オーバーフロー判定には使えないようでした。

仕方ないのでいろいろ考えたのですが、掛け算した結果を a で割って b と等しくなれば計算できている(オーバーフローしていない)と判定してみることにしました。

うちでは動く乗算オーバーフロー判定

いくつかのケースを試しましたが、正しく判定できたので、実装もシンプルなので上記のアプリはこの方法でオーバーフロー判定してます。

この方法(実装は Unity なので C#ですが)で、正しく64ビット整数の最大値 922京3372兆368億5477万5807 のカウンターストップが達成されたスクリーンショットがこちらw。(あいしさん、ここまでプレイしていただいてありがとうございます)

64ビット整数の最大値でちゃんと止まってます

II. 正攻法

乗算の処理系に依存しない判定方法が難しい。
加算の時と同じように考えると、以下のようになると思います。

a と b の積が LONG_MAX を超えるには、少なくとも a か b のどちらか一方が √LONG_MAX 以上である必要があるので、

(1) a と b どちらも √LONG_MAX 未満の場合、オーバーフローはしない

(2) a のみが √LONG_MAX 以上の場合、a ÷ √LONG_MAX × b が √LONG_MAX 以上の場合、オーバーフローする

     b のみが √LONG_MAX 以上の場合、b ÷ √LONG_MAX × a が √LONG_MAX 以上の場合、オーバーフローする

(3) a と b どちらも √LONG_MAX 以上の場合、オーバーフローする

しかしこのロジックをコンピューター上で正確に実行するのは困難です。なぜなら(2)の計算の途中に小数が入り込み、誤差が生じる余地があるからです。というわけで、積の正攻法判定はとりあえずあきらめました。

どなたか良い方法があれば教えてください…。(–;

[2017.03.02 追記]
コメント欄に良い方法をいただいてしまいました。

 「a < LONG_MAX / b が成り立つ場合、a * b はオーバーフローしない」と判断できそうです。今後はこの方法でやろうと思います。(^^;

減算(ー)、除算(÷)の場合は?

a も b も正の値だとすると、減算で(符号の逆転はあるにせよ)オーバーフローするケースはありません。

また除算でも(切り捨て誤差が発生するにせよ)オーバーフローするケースはありません。

まとめ

  • 64ビット整数演算のオーバーフロー判定は、処理系依存のコードであれば上記のような簡単な方法で記述できる。実用上はそんなに問題ないはず。
  • 符号付き64ビット整数の乗算オーバーフロー時、答えが負の数になると思ってはいけない。
  • とりあえず「積を元の数で割ってみて元に戻るか」で判定してみた iOS/Android アプリをリリースしていますが、今の所NGケースは見つかっていません。
  • [2017.03.02 追記] 乗算の判定に関してコメント欄で「a < LONG_MAX / b が成り立つ場合、a * b はオーバーフローしない」というやり方を教えていただきました。このやり方のほうが、環境依存しないという意味で、よさそうですのでお勧めいたします。(^^;

ワイ、円周率を割り切った模様 → 円周率=7825万6779 分の 2億4585万922

こんにちは。 3.14から始まる円周率はどこまでも続く男のロマン・・・そんな風に考えていた時期が、ワイにもありました。 「円周率が10桁で割り切れた」とかいう嘘記事が虚構新聞から出回ったりしたこともありました。 しかしさっきプログラムを作っていろいろ計算していたところ、円周率が割り切れてしまったので報告させてください。 そもそもは、円周率を分数で表現する手法を最近知り興味を持ったのがきっかけです。例えば

Screen Shot 2015-12-09 at 1.56.39 PM

とかです。7分の22が円周率のそこそこの近似値(3桁まで正しい)になっています。 次に有名なのが、

Screen Shot 2015-12-09 at 1.56.07 PM

らしいです。この113分の355はなんと7桁まで正しい近似になってます。3桁の整数2つ覚えるだけで、円周率7桁分の精度が得られるとは何ともお得な数です。 ここで疑問が湧きました。 この調子で分母の整数値を上げていったらどうなるのだろうか・・・? 本来数学でのやりかただと、ここで「連分数」などを持ち出すようなのですが、幸い?自分はそのあたりは忘れてしまったソフト屋なので、力技で結論だけだす以下のようなプログラムを作りました。言語は JavaScript で、実行には Node.js を使いました。

<pi.js>

分母を1から1ずつ上げていき、分子は既知の円周率 Math.PI から逆算してます(ちょっとずるいですが・・)。   実行結果は以下の通りです。

なんと、分母が7825万6779になったところで誤差が0になって割り切れてしまいました。やばい。 つまり

Screen Shot 2015-12-09 at 2.06.53 PM

であることが確かめられてしまいました。 少なくとも JavaScript さんは 円周率 = 7825万6779 分の 2億4585万922 だと判定しました。 どこか計算間違っているんでしょうかね・・・?

だれか詳しい人教えてください。

bc コマンドが思った以上に便利なので紹介します

こんにちは。 久しぶりにプログラマー向けの記事です。 bc と言うコマンドが、知れば知るほど素晴らしすぎるので、その凄さを知っている範囲で紹介します。「そんなの知っている」と言う方はスルーでお願いします。

bc コマンドとは

Unix の標準コマンド(SUS Shell and Utilities)の1つで、任意精度の計算を行うコマンドです。例えば Mac OS X は Unix ですので、標準でインストールされています。Windows で使用したい場合は別途インストールする必要が有ります。

使い方(基本編)

起動

Mac OS X で使用する場合の例を紹介します。 まず Dock からターミナルを起動して bc と入力します。

するとクレジット情報が表示され、入力待ちになります。プロンプトはありません。

式の入力

例えば “1+2” を計算したい場合は、そのように入力してリターンキーを押します。

答えは “3” ですね。 デフォルト状態で、四則演算(+, -, *, /)、剰余(%)、累乗(^)、平方根(sqrt)などが使えます。 ちょっとした計算、例えば平均値の計算などが、通常の電卓よりは計算しやすいと思います。

小数点以下の桁数を指定

デフォルト状態では、小数点以下の値は切り捨てられますが、scale と言う特殊変数に値を設定することで、小数の計算結果も得られます。例えば、小数点以下3位までの結果を表示させるには以下のようにします。

終了

終了するときは quit と入力します。

応用編

2進/10進/16進の相互変換(ibase, obase)

このあたりから非常に有用になってきます。 bc は、ibase, obase という変数に値を指定することで、入力と出力に使用する進数を自由に指定できます。

16進数 98A0B0223F を 10進数に変換する

10進数 1234 を2進数に変換する

10進数 987.6543 を 16進数に変換する「16進の小数」なども普通に扱えます!

ひとつ注意点があります。 ibaseを10以外の値にしてしまうと、それ以降入力する値はすべてその進数で入力しなければなりません。例えば以下の例は思うように動作しないでしょう。そのため、obaseを ibaseより先に設定するのが無難です。

16進->10進変換(失敗例)

π の計算(初等関数の使用)

起動時に “-l” (小文字のエル)オプションを付加すると、サイン (s), コサイン (c), アークタンジェント (a), 自然対数 log (l), exp (e), ベッセル関数 (j) が使用できます。このとき scale は自動的に 20 に設定されます。

ここで、アークタンジェント1が π/4 だと言うことを利用し、a(1)*4 で π を求めています。これは数値計算の定石です・・・よね。 scale を 1000 とかにしても、いけます!

そう、π は男のロマン・・・。 誤差はほとんどありません!最後の桁は(4でかけてることもあり)合わないことが多いですが、その1つ前の桁は正しいと思っていいようです。(厳密な話をすると長くなるので割愛します・・・)

π を16進数で表示

ここで obase=16 にすると、16進数で π が表示できたりします!

16進数の π が標準コマンドで、こんな手軽に表示できるとは! しかもPCの計算能力が許すまでいくらでも!

\(^o^)/

オイラー数 e についても e(1) とすれば表示されるので、同様のことが可能です。すごいです。 プログラマーとしては押さえておきたいコマンドですね!

サイン、コサインをインテルの CPU で計算すると少しバグっているらしい

こんにちは。

ちょっと前にどこかの偉い人が「女性にサイン、コサイン教えても仕方ない」ような発言をして炎上したのは記憶に新しいところです。面白いですね。

「女の子にサインコサイン教えて何になる」 鹿児島県知事の発言がネットで非難 発言撤回の会見動画も公開 – ねとらぼ
http://nlab.itmedia.co.jp/nl/articles/1508/28/news145.html 

「いやいやサイン、コサイン使うでしょ」という反論には完全に同意です。それはよいのですが、プログラマー的な視点で見れば「サイン、コサインはコンピュータでどうやって求めているか」を説明できてやっと安心(?)ではないでしょうか。

そこでちょっと復習と思って調べてみたら、なんかインテルのCPUのバグ?の話とか出てきてわけが分からなくなってきたので、まとめておきました。

sin(x) の求め方(基本)

理系の方は学校で習ったと思いますが、テーラー展開した多項式で求めるのが常套手段です。

例えばサインの値は、以下の多項式で表現できます。

Screen Shot 2015-10-21 at 10.26.30 AM

自然科学のための数学I/II(2014年度)- 琉球大学
http://www.phys.u-ryukyu.ac.jp/~maeno/sizensuugaku/lec11_sin.html

これを実際に計算するサンプルプログラムとかはネット上にごろごろしてるので、ここでは挑戦しません。ここでは、この計算が最近のコンピュータのどの部分で行われるかに注目してみます。

コンピュータのどの部分で計算しているのか

コンピュータで sin(x) の値を計算させるときは、昔も今も上記の多項式が使われているようです。(※他のアルゴリズムもありますがあまり使われていないらしい)

最近(と言っても 8087 にすでにあったようなので20年以上前から)はハードウエアレベルでその機能が提供されています。別の言い方をすると、sin(x) の値を求めるアセンブラ命令があるということです。インテルの x87 では FSIN, FCOS などです。

なので当然 sin(x) の実装にはこのアセンブラ命令 FSIN が使われていると思いますよね?

しかし念のため確認してみると意外な事実が判明しました。確認したのは GNU の C 標準ライブラリ glibc のソースで、バージョンは 2.22.90 です。

GNU C Library (glibc)

https://www.gnu.org/software/libc/

おそらく sin(x), cos(x), tan(x) とかはそのハードウエアのアセンブラ命令を叩くだけのはず。

sin(x) とかはアーキテクチャ依存の実装になるので、double __sin(double) の実装があちこちにあって悩ましいですが、とりあえず x86_64 アーキテクチャでは、

  • sysdeps/x86_64/fpu/multiarch/s_sin.c
  • sysdeps/ieee754/dbl-64/s_sin.c

の実装が有効のようです。すると、

<sysdeps/ieee754/dbl-64/s_sin.c>

Screen Shot 2015-10-21 at 1.11.21 PM

https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/ieee754/dbl-64/s_sin.c;hb=HEAD#l279

あ、あれ?

なんか思っていたのと違いますね・・・と言うか、完全にソフトウェア的に計算しています。

なんでハードウエアサポート使わないの?

せっかくハードウェアサポートがあるのに何で使わないんだろうか・・・。って思っていろいろ調べてみましたが、以下ページを見つけました。

Intel overstates FPU accuracy – 06/01/2013

http://notabs.org/fpuaccuracy/index.htm

Screen Shot 2015-10-21 at 1.17.29 PM

リンク先を見てみると「インテルの FPU (x87) のコサイン、タンジェント命令は、スペック通りの精度がでない場合がある。」と言った趣旨のことが書かれています。

また以下のページにも興味深いことが書いてあります。

How does C compute sin() and other math functions? – Stackoverflow

http://stackoverflow.com/questions/2284860/how-does-c-compute-sin-and-other-math-functions

Screen Shot 2015-10-21 at 2.35.57 PM

この質問に対する回答によると、「2011年の10月以降 x86-64の Linuxではこの(ソフトウェア)コードが使われており、明らかにFSINより速いSince October 2011, this is the code that actually runs when you call sin() on a typical x86-64 Linux system. It is apparently faster than the fsin assembly instruction.)」とのことです。

というわけで、現在かなり普及している x86_64 アーキテクチャー(Windowsも Mac も大部分が採用している)の CPU の三角関数命令 FSIN は、速度、精度などが問題視されており(少なくとも glibc では)、別途ソフトウェア的に実現されているようです。

他の実装ではどうなっているかは不明ですが、glibc での実装と似たようなことをやっているのではないかと思います。

インテルも大変なんだな・・・。

まとめ

  • サインなどの三角関数の値はテーラー展開を使用した有名な式を昔も今も使って計算していることが多い。
  • 20年以上昔から浮動小数点数演算用のFPU(コプロセッサー) には三角関数の値を計算する命令(ハードウェアサポート)がある。
  • しかしインテルの x86_64 系アーキテクチャーのこの命令は精度及び速度に問題があるらしく、少なくとも glibc 2.22 ではFPUのサイン命令は使っておらず、ソフトウェア的に計算しているらしい。

という感じでした。

何はともあれ glibc の sin 関数のソースは勉強になるので、数値計算に興味のある方には一度じっくり見てみることをおすすめします。

 

 

「性別」を表す変数名をアレにするのやめませんか?

こんにちは。

プログラマーあるあるだと思うのですが、人物を表すクラスなどをしばしば以下のように定義すると思います。

typedef _Person {
    char* name;  //名前
    int age;     //年齢
    int sex;     //性別 (0:男性 1:女性) <=== 恥ずかしい (><)
} Person;

 (※言語は何でもいいんですけど、とりあえず C で記述します)

「性別」って辞書で調べると「sex」って出てくるので、おおそうかとばかりにこれを変数名にしているコードが実に多いです。

いや間違いではないし、むしろ正しいのですが、個人的にはなんか恥ずかしくてどうしてもやりたくありません。

「sex = 1;」とか書きたくない。

「sex が 0 のとき・・・」とか読みたくない。

セクハラ認定されそう。

などなど不安でたまりせん。

そこで代案をいくつかあげましたのでプログラマーの皆さんにおかれては、今後そのようなコードを記述する際にはご検討ください。

代案1:そこだけローマ字にする

ぐぐってみると以下のようなコードを使っているサイトがありました。

typedef _Person {
    char* name;   //名前
    int age;      //年齢
    int seibetsu; //性別 (0:男性 1:女性) <===
} Person;

個人的には「これは無い」と思いますが、例の単語を使うよりはましな気もしました。しかしおすすめではありません。自分がコードレビューワーなら却下したいところです。

代案2:”gender” に置き換える

個人的なおすすめはこれ。”sex” という単語の代わりに “gender” (ジェンダー)と言う単語を使う方法です。ロジックはそのままなので簡単ですね。ちなみに weblio 様のサイトによると gender の意味は次の通り。

gender【名詞】
1【文法】 性.
2《口語》 (人の)性,性別,ジェンダー 《社会的,文化的意味づけをされた男女の差異》.

[weblio – http://ejje.weblio.jp/content/gender]

いろいろ調べてみると、gender は sex よりも「社会的な性」という意味で使われることが多いとか書かれてたりしますが、Wikipedia 様の「Sex and gender distinction」(2015年10月18日閲覧)という記事によると婉曲表現うんぬんとの解説があるので、今回の目的にも使えると思います。っていうか、自分は使います。

typedef _Person {
    char* name;   //名前
    int age;      //年齢
    int gender;   //性別 (0:男性 1:女性) <===
} Person;

「ジェンダーが0のとき〜」とか自然に読めます。やった!

代案3:男性であるかどうかのフラグに置き換える

これもいい方法です。「性別」ではなく「男性かどうか」のフラグに置き換える方法です。

typedef _Person {
    char* name;   //名前
    int age;      //年齢
    BOOL isMale;  //性別 (TRUE:男性 FALSE:女性) <===
} Person;

但し、こうすると「男性でも女性でもない」状態が表現できなくなります。それが必要な場面はそれほど多くはないと思いますが、昔自分がかかわった医療機器のコードでは、性別は「男性、女性、不明」と3つの値が取れるように定義されてました。

この方法にはもう1つ心配な点があります。それは「なんで真の時に男性を表すのですか?これは男尊女卑的ではないですか?」というクレームがどこからともなく来そうな予感がするところです。

それに備えてコードを以下の様にしておけばスキはありません。

typedef _Person {
    char* name;    //名前
    int age;       //年齢
    BOOL isFemale; //性別 (TRUE:女性 FALSE:男性) <===
} Person;

これなら真のときに女性を表すので妙なつっこみもできそうにないですね!

以上、真面目な提案なのでよろしくお願いいたします。

vim を less とか more の代わりに使うと便利

こんにちは。

久しぶりに小ネタ書きます。

プログラマーの皆さんはコマンドライン(ターミナル)で作業されることも多いと思いますが、コマンドの結果が長くて1画面に収まらない場合どうしているでしょうか?

「スクロールしてターミナルの履歴を見る」でもよいですけど、ターミナルの設定によっては見たい結果がバッファに残ってなかったりしますよね。あと検索できないのが辛い。

なので less とか more というコマンドに渡して見る方法が一般的なのではないでしょうか?
less だと “/” を押せば検索もできますし。

しかしこの less なんですけど、なんとなく vim っぽい操作性でありながら vim ではありません。

そこでいっそのこと vim を less の代わりに使えばいいのではと思いついて、5年くらい前からやってますが、いい感じなので紹介です。

「そんなの普通にやっている」という方はスルーしていただけるとありがたいです。

確認した環境

Max OS X Yosemite 10.10.5

やり方

vim はファイル名として “-” (マイナス記号) を指定すると、標準入力を編集対象にできます。また、vim は “view” という別名を持っていて、この名前で起動するとリードオンリーモードになります。

この2つのオプションを使えば vim を less の代わりのページャーとして使えます。具体的には、

$ ls | view -

などのようにします。

こうすれば、検索はもちろん、vim の機能がすべて使えるのでいろいろ便利です。

使用例

例えば Cocos2d-x のソースファイルの一覧を見たい場合、

$ cd cocos2d-x-3.8
$ find . | view -

このようにします。すると結果は以下のような感じになります。

Screen Shot 2015-10-10 at 12.54.03 PM

14,787行もでました。

しかしここは vim ですので、あとは何でもできます。例えばこのなかに “SpriteBatchNode” を含む行だけを残したい場合

:%!grep SpriteBatchNode

などと打てば、(「リードオンリーですよ」って警告は無視)

Screen Shot 2015-10-10 at 12.57.23 PM

となりました。
クラス SpriteBathcNode に関連する C++, JavaScript, lua のファイルが6件あったってことですかね。

さらに例えばファイル名は不要で、ディレクトのリストにしたい場合は、ここから

:%s/[^/]*$//

とかやって、

Screen Shot 2015-10-10 at 1.03.39 PM

重複した行は

:%!uniq

などで消せるので

Screen Shot 2015-10-10 at 1.05.31 PM

こうなりました。
これでディレクトリのリストができました。自由自在です!

上記のように結果を編集してしまうと終了時に怒られるので、結果が不要な場合は

:q!

のようにします。

というわけで vim を less の代わりに使うのはおすすめです。

プログラマー歴20年ですが goto がどんなに有用なのか聞いてほしい

こんばんは。

ちまたの新入社員教育では「goto を使うとプログラムが汚くなるから使用禁止ね」と教えられ、会社では goto の入ったコードは忌み嫌わせているようです。自分も20年くらい前に入社した会社でそのように教えられた記憶があります。しかしいまいち納得がいかないまま今に至っています。

以下に、自分が知る限り「goto を使ってよかった!」「goto を使ったら彼女ができました!」「gotoを使い始めてからパチンコも勝ちまくりです!」といった事例をあげていきたいと思います。例によって反論は歓迎しますので、一緒に正しい結論にたどり着きましょう!

なお、言語は限定しませんが、C/C++ での例をあげていきます。

多重 for ループからの脱出に有用

まずは1番わかりやすい例です。普通の for ループだと、break で抜け出すことができますが、for がネストした2重以上のループの途中で、その一番外のループから抜け出したい場合、どうしたらよいでしょうか?goto を使うと美しく記述できます。

goto を使わない場合、そのためのフラグを用意する必要が出てきます。 これは goto をつかった記述とどちらが美しいですかね?

エラー検知時の処理に有用

次に外部システムとのやりとりを行う関数中でのエラー処理を考えてみましょう。一連の処理の途中、復旧不能なエラーに遭遇し、処理をあきらめる場合に goto が便利です。

 

gotoを使わない記述では、フラグを用意するくらいしか思いつきません。やはり goto のパワフルさが際立つ一例です。

[※2015年9月7日 @ooee81 さんのご指摘に従い、return では実現できない例になるよう、エラー発生後に共通の処理を追加しました。]

ユーザー対話式処理の記述に有用

アクションゲームではあまり必要になりませんが、ユーザーの入力にしたがってシナリオを進めていくようなRPGのような処理を記述する場合、goto が欲しくなりますよ。

ユーザーがキャンセルしたときに、1つ前の選択画面に戻る必要があると思いますが(この例では、攻撃を選択した後、攻撃方法の選択でキャンセルした場合)それってgotoを使う記述がもっとも適していると思うんですよ。

例外でも似たようなことできるんじゃないですか?

場合によってはできます。しかし例外は関数を飛び越えられるので危険です。特にC++ではメモリリークの元。まあガーベージコレクションのある処理系(例:Java)なら例外でもいい場合もあります。

Linuxの作者も goto が大好き!

「そんなこと言ってるのはあなたくらいじゃないですか?」と言われそうなので、goto大好きな有名人を紹介します。泣く子もだまるLinuxカーネルの開発者リーナス・トーバルズさんです。

Screen Shot 2015-09-07 at 9.07.12 PM

2015年9月7日現在最新のLinux カーネルのソースコードの一部をみてみましょう。

goto がいっぱい!\(^o^)/

https://github.com/torvalds/linux/blob/master/kernel/signal.c

Screen Shot 2015-09-07 at 9.08.56 PM

 

別に彼が goto を使っているから使っていいんだと言うつもりはありませんが、世界的なプログラマーが世界中で使われているコードの中で goto を多用しているという事実は興味深いと思って紹介しました。

まとめ

Linux 開発者のリーナス・トーバルズは goto 大好きらしいです。

そうは言っても、使い方を間違えると、わかりにくいプログラムを生み出す元になるのはご存知の通りですので、むやみに使うべきではありません。

というわけで嫌われ者の goto ですが、言語によっては(特にC/C++)時として有用だと思います。

ネット上で公開されているコードをコピペする前に確認すべきこと

こんにちは。

佐野研二郎氏による2020年東京五輪エンブレムのデザインがパクリではないかという疑惑が持ち上がり、ついには使用停止に追い込まれました。

さて、アプリ開発をやっていると、ことあるごとに問題に遭遇し、その度にググっている(Google検索している)という方が多いとおもいます。その際に検索して見つかるコードを、自分のコードにコピペしてよいのでしょうか?

肌感覚ではだいたいわかっているつもりですが、せっかくなので明文化してみました。(問題等のご指摘歓迎します)

公開する予定のないアプリへのコピペ

もしコピペする先が、なんらかのテスト目的などで、公開する予定のないアプリの場合、問題はありません。がんがんコピーして使いましょう。

特に何かの機能が実現できるのかできないのか、本格的な開発に入る前のフィージビリティテスト(実現性試験)はこのケースに当てはまります。

注意すべき点は、「最初は公開するつもりでなく作成したコードを、いつのまにか公開する本番コードにも使ってしまった」ということがいかにも起こりそうなことです。特に会社で開発している場合、前担当者が作ったコードなどを引きついだ場合などもちょっとリスクがあります。

「公開する予定がない」というのは、言い換えれば「それで儲けないし、他人の儲けも阻害しない」という意味です。

公開する予定のあるアプリへのコピペ

会社の仕事などでコード開発している場合、コピペして良いかどうかはケースバイケースです。以下いくつかの例を考えてみます。

使用条件(ライセンス)が明記されていない場合

技術ブログなどで「個人の覚書です」などとだけ書かれていて、使用条件(ライセンス)についての言及がないことがよくあります。この場合、そこに掲載されているコードをコピペして良いかどうかは、それを公開している人(ブログ作者)にメールなどで「あなたが公開しているコードを、会社で使用するコードに部分的に使用したいけど問題ないですか?」と確認するのが確実です。しかし自分はそこまでやることはないです。じゃあどうしているかは後述します。

使用条件(ライセンス)が明記されている場合

技術ブログなどで「本ブログのコードは自由に使用してください」などと明記されている場合、ほとんど問題は発生しないはずです。コピペしましょう。(この場合、リスクは0ではない)

もちろん「無断転用などは禁止です」と書かれていたら、だめです。

オープンソースソフトウェアのコードの場合

GPL, Apache ライセンス、MIT ライセンスのもとで公開されているコードの一部を使いたい場合は、「コードの改変」に相当するため、ライセンス規約にしたがう必要があります。

GPL ライセンスのコードを使ってしまうと、自身のコードも GPL のもと、公開する義務が発生します。おそらくアプリ開発においてはこれは受け入れ難いはずです。コピペはあきらめましょう。

Apache, MIT ライセンスの場合、自身のコードには同等のライセンスを適用する義務はないですが、もともとのコードの著作権情報とライセンス情報を、わかりやすい場所に表示する必要があります。たとえばアプリであれば、アプリの著作権表示に「このアプリはXXXXXのコードを使用しています」などと明記する必要があることになります。個人的には、ほんのちょっとのコピペのためにこのような義務が発生するのは、のちのち負担になるので、あまりやりたくはないです。しかしコピペは禁止されてはいません。

(参考ページ)

ライセンスの選択を恐れる必要はありません – Qiita
http://qiita.com/tadsan/items/99d816e78ca429093b75

じゃあどうすればよいのか

あなたが開発しているアプリが会社名義で公開予定であったり、ものすごい利益をもたらす可能性がある場合は、基本的にコピペはしないほうが確実です。

コピペはばれます。ソースコードのままだともちろんですが、コンパイルした後でも場合によってはばれます。ダウンロード数が10とかのアプリなら、そもそも調査されないと思いますが、まちがって何億、何十億の利益を生んだり、あるいは他人の利益を阻害したりすると調査される可能性がでてきます。

自分の場合は以下の方法を取っています。

  1. コピーしたいコードを100%理解する
  2. 理解した内容を、自分のコーディングスタイルで一から書く
  3. それでも結果としてまったく同じコードになってしまった場合、「このコードは標準的な技術を持つ技術者であれば、別個に思いついた可能性がある」と判断して、そのまま使う

「自分のコーディングスタイル」というのは、たとえば変数名や関数名などです。コピペがクロ認定されるのは、だいたい「こんな変数名、普通つけないだろ」というのがかぶってたりする場合です。(ただし変数名だけ変えろと言っているのではありません。)

ここまでやっておけば、万が一裁判にでもなったりしても、まず問題ないはずです。

まとめ

  • 公開予定のないものへのコピペは問題ないが、意図せず公開されることもあるので注意。
  • コピペは他人の利益を阻害する可能性があるので特に許可された場合以外やってはいけない。
  • コピペしたいコードは、そのコードを自分で100%理解して、自分で一から書くべき。

 

外資系企業でプログラマーを10年やってわかったこと(1)

こんにちは。

自己紹介の欄にも簡単に書いてありますが、2015年3月まで、ほぼ10年(正確には9年5ヶ月)某アメリカの外資系企業でプログラマー(社内での呼び名はソフトウェアエンジニア)をやらせていただきました。その時のことをつらつらと綴ってみました。

中途採用なら学歴に関係なく採用される。ただしタイミングが超重要

自分は転職(中途採用)で採用していただきました。自分は私立大学の付属高校に通っていたこともあり、一般受験などはせずに普通の?私立大学の物理学部に通い、修士までいました。

しかしこのとき新卒で就職活動をしたとき、あまりにも希望の企業に入れないのでびびりました。「最近は学歴あまり関係ないよ」って誰かが言ってたんですけど、気のせいですよね。自分も若かったので、信じていました。まず学歴でフィルターされているのは当たり前です。学歴フィルターがされていない企業は、人気のない企業です。

しかたなく某日本企業に入社しましたが、3年もたずに転職活動を始めてしまいました。(2005年)

転職活動は、たしかリクナビNEXTにエントリーしたら、転職エージェントの方がいろいろ候補を持ってきてくれるので、非常に楽でした。有給をとって面接試験に行くのは気が引けましたがよい思い出ですね。

そのエージェントの方にいろいろ紹介していただき、5社くらい面接をやりました。結果、日本企業は受からなかったのですが、外資系企業2社から内定をもらいました。

そのとき自分にとって幸運だったのは:

  • 勤めていた企業は残業代はちゃんとくれていたので年収はわりと高かった
  • 英語は昔から得意だった (当時TOEIC865点)
  • ゲームのコンテスト入賞の経験がある

といったあたりを評価してもらえたことです。

見事なまでに日本企業には採用してもらえなかったのは、自分が話が下手なこともあるのですが、なんといっても学歴が足りなかったのだと思います自分の経験では、外資系企業の中途採用は、学歴は新卒採用の時ほどは重視していないようです。

入社後、中途採用の方が後から何人も入ってきましたが、募集は年中行われているわけではなく、アメリカの親会社からの許可が出ている期間のみなので、運良くそのような期間に応募すると、採用される確率が高くなります。

転職活動と恋愛はタイミングが非常に重要です。

英語で仕事ができるかどうかは慣れ。しかし上限は努力次第

外資系なので、電話会議や出張などで英語をつかう機会がたくさんありました。

入社当時英語は得意だと思っていましたが、電話会議に出ても相手が何を言っているのかほとんどわかりませんでした。恥ずかしくて会社辞めようかと思いました。

しかたないので「英語が苦手な変な日本人」を演じます。すると相手も「ああ、こいつは英語にがてなんだな。よし、ゆっくり話してあげよう」となります。

そんな感じで悔しさで枕をぬらす毎日を、1年くらいつづけると、だんだん彼らの会話が理解できるようになっていきました。今思えば聞き取れなかったのは、英語だけの問題ではなく、そもそも社内用語になれていなかったのも大きな原因でした。

もう1つは、自分はアメリカ人のきれいな英語に慣れ過ぎていて、インド人や中国人の独特の発音に対応できていませんでした。そのあたりになれていったことも、理解できるようになった一因です。

同じ職場にいる同僚も、中には英語が苦手という人もおり、確かにその人が書く英語のメールとかは文法が間違えだらけなのですが、電話会議などはちゃんとこなされていました。結局、英語で仕事ができるかどうかは、TOEICの点数とかで測れず、慣れているかどうか、だと思います。

ただし、英語がびっくりするほどうまい人もいて、いろいろ聞いているとそういう人は相当勉強しているようです。ただ英語で仕事ができるだけにとどまらず、英語ですごく仕事ができるようになるには、慣れだけでは不十分です。

ある日突然クビになることはない。しかし評価が悪いと転職を勧められる可能性はある

よくアメリカの企業などで、「ある日上司に呼び出され、解雇を告げられて、その後席に戻ることも許されずに会社を追い出された」という話を聞きます。

自分がいた会社は、資本はアメリカのものでしたが、会社は日本のものでしたですので、日本の法律(労働基準法)が適用されます。なので、上記のような「ある日とつぜんクビ」は日本ではできないようです

自分のいた会社は労働組合がありました。しかし日本の外資系企業には、労働組合がないところもあるそうです。自分のスキルに自信がある人にとっては労働組合にはあまり必要性は感じないと思いますし、そういう人材が外資系企業に集まっているわけなので、労働組合はあってもなくてもいいかなと思います。

そうは言っても、成果主義はかなり徹底していました。毎年目標を立てて、年末に達成度合いを上司に報告します。上司がそれを見て評価を出し、評価が良いと基本給があがりますが、評価があまりにも悪いと、基本給が下がることもありました。さらに基本給が下がるような評価を連続で受けると、「転職支援」をもちかれられます。これは受けるかどうかは選択できますが、こうなってしまうともう出世の道は閉ざされています。

同僚同士ライバル意識が高くて職場はいつもピリピリしている、なんてことはない

外資系企業と聞くと、みんな成果をあげようと必死で、同僚同士でも足の引っ張り合いをしているようなイメージがありますが(自分だけ・・・?)そんなことは全くありませんでした。よかった。

むしろみんな自分に自信があるから、余裕たっぷりで、何を聞いても丁寧に答えてくれます。嫌がらせをされるようなら、むしろ大したものです。

ただし上記は職場での話なので、裏では何を言われてたり、嫌がらせをされているかも知れませんが、それは日本企業でも同じところです。

外資系企業でもエンジニアの待遇はそんなにすごくない。金融機関はすごいらしい

よく外資系企業だと「新卒から年収1千万超え」などという話を聞きますが、少なくとも自分の経験したエンジニアという職種ではそんなことはありません。外資系金融機関は、がちで新卒から年収1千万、平均年収3千万円とかあるらしいですね。うらやましい。

(つづく・・・)

なんだかプログラマーっぽいことを書く前に長くなってしまったので、今日はここまでにしておきます。後日つづきを書こうと思います・・・。

 

日本人プログラマーにありがちな10の間違った英語の読み方

今年の3月まで某外資系企業でプログラマーを10年やらせていただき、いろいろありました。

海外のエンジニアと電話会議やミーティングをやる機会がよくあったのですが、日本でカタカナで覚えた用語がしばしば通じなかったり、向こうがなんか知らない用語を使ってるなあと思ったら実は知っている単語だったりしたことがよくありました。

自戒も含めてまとめてみました。

(※国際的に通じる発音を認識して、海外にも通用する人材に近づくことが本稿の目的です)

以下、多分通じないカタカナ表記を赤そこそこ通じそうなカタカナ表記を青で書きます

Cocoa

Mac OS X や iOS で使われているフレームワークの名称です。これは「ココ」に近い発音ですココアだと思っていて聞き取れず、悔しい思いをしました

cocoaの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/17035/m0u/

Opaque

不透明度のことです。昔会社の先輩が「オパキュー」と言っていたので、そのように読んでしまっている日本人はいなくもないと思いますが、英語圏では「オペーク」に近い読み方をします。自分はオパキューと言われるとオバケのキャラクターしか思い浮かびません。

opaqueの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/59219/m0u/opaque/

Height

高さのことです。もちろん「ハイト」と読めばだいたい通じます。スペルから判断して「ヘイト」と読んでしまう日本人が多いので要注意です。

heightの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/39780/m0u/height/

Hierarchy

階層構造のことで、日本語では「ヒエラルキー」と書くことが多いとおもいます。日本人と話す時はそれでもよいのですが、英語圏の人の発音をあえてカタカナにすると「ハイアラーキー」のように聞こえました。相手によって使い分けましょう。

hierarchyの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/40332/m0u/Hierarchy/

Tutorial

日本語では「チュートリアル」です。お笑い芸人でそういう名前の人がいた気もしますし。カタカナにはしづらいので、これでいいと思うのですが、英語圏の人がしゃべると、あえてカタカナにするなら「テュトーリアル」のように聞こえます。「テュ」が日本語にないのが問題なんですかね。

tutorialの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/89034/m0u/tutorial/

Ping

ネットワークがつながっているかどうか調べるコマンドです。自分も周りの人も日本では「ピング」と読んでいる人が多いと思いますが、英語圏の人は「ピン」のように言ってました。考えてみると、現在進行形の “-ing” の発音のときは、最後の g はあまり発音しないですが、それと同じことですよね。ピングっていうと某ペンギンのキャラクターのことだと思われるんじゃないですかね?

Github (gif, gimp)

プログラマー界では著名は Git を使用した Web 共有サービスです。自分は「ジットハブ」だと思っていたのですが、「ギットハブ」と読むのが正しいようです。同様なものに画像ファイルの gif, 画像加工ソフトウエアの gimp もありますが、それぞれ「ギフ」「ギンプ」が多数派のようです。 gif は開発者が「ジフ」だと言っているので「ジフ」、gimp は「ギンプ」が多数派のようです。([2015年6月10日 訂正] @nekobata_kaigi さん、ご指摘ありがとうございます)

Github – Wikipedia
http://ja.wikipedia.org/wiki/GitHub

Warning

コンパイルするとよく出てくる「警告」です。日本では「ワーニング」と読む人が(少なくとも自分の周りでは)多いですが、英語圏の人の発音は「ウォーニング」に近いです。「War (戦争)」は「ウォー」って言いますよね?

warningの意味 – 英和辞書 – 英語辞書 – goo辞書 http://dictionary.goo.ne.jp/leaf/ej3/93161/m0u/Warning/

Null

初期化してないポインターがよくこれになって悩まされます。これも日本では「ヌル」と読む人が(少なくとも自分の周りでは)多いですが、英語圏の人の発音は「ナル」に近いです。しかしこれはドイツ語では「ヌル」のように発音するという話もあるので、英語圏でも「ヌル」と言っても通じる気がしてます。ソースは自分です。それに日本人相手に「ナル」とか言うと嫌われる予感がすごくするので、相手によって使い分けると良さそうです。

nullの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/58015/m0u/null/

Matrix

行列のことです。某有名映画のタイトルにもなっているので「マトリックス」と読む日本人が多いと思いますが、英語圏での発音は「メイトリックス」のほうが近いです。これくらいなら時間とともにきづくんですけど、怖いのはこれの複数形が matrices なことで、カタカナにすると「メイトリシーズ」のように聞こえます。これは知らないと何百回聞いても理解できません。

matricesの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/52376/m0u/matrices/

番外編

Width

幅のことです。非常に使用頻度が高いのですが、日本人には絶望的に発音が難しいです。カタカナにするのは無理です。自分はあきらめて「ホリゾンタル サイズ」とか言い換えることにしてました。

widthの意味 – 英和辞書 – 英語辞書 – goo辞書
http://dictionary.goo.ne.jp/leaf/ej3/94624/m0u/width/

最後に

あくまでケースバイケースで、正しいか間違っているかよりも、通じたか通じなかったかを重視すべきだと思います。