KotlinのFizzBazzで35億になったら`ブルゾンちえみ With B` #teratail_kt


`#teratail_kt`にて([UbuntuにKotlinをインストールしてハローワールドまでやってみた #teratail_kt](https://qiita.com/n0bisuke/items/686c1717a894713fdd06))から引き続き。

FizzBazzだけだとつまらないので35で割り切れる場合に`With B`にします。

それだけなんだけど結構勉強になりました。

## 通常のFizzBazz

```fizzbazz.kt
fun main(args: Array<String>) {
	for (i in 1..100) {
        when {
            i % 15 == 0 -> println("FizzBuzz")
            i % 3 == 0 -> println("Fizz")
            i % 5 == 0 -> println("Buzz")
             else -> println(i)
        }
    }
}
```

実行すると数字が100までカウントアップしていきFizzのときとBazzのときとFizzBazzのときは表示が変わります。

```
1
2
Fizz
4
Buzz
Fizz
7
```

## Kotlinで35億を扱う

上記コードでそのまま35億(`3500000000`)を扱おうとしてみます。

```35.kt
fun main(args: Array<String>) {
    for (i in 1..3500000000) {
        when {
            i % 15 == 0 -> println("FizzBuzz")
            i % 3 == 0 -> println("Fizz")
            i % 5 == 0 -> println("Buzz")
             else -> println(i)
        }
    }
}
```

エラーになりました。Intの桁数っぽいですね。

```
$ kotlinc ./35.kt -include-runtime -d 35.jar
35.kt:4:13: error: operator '==' cannot be applied to 'Long' and 'Int'
            i % 15 == 0 -> println("FizzBuzz")
            ^
35.kt:5:13: error: operator '==' cannot be applied to 'Long' and 'Int'
            i % 3 == 0 -> println("Fizz")
            ^
35.kt:6:13: error: operator '==' cannot be applied to 'Long' and 'Int'
            i % 5 == 0 -> println("Buzz")
            ^
```

型推論で変数iがInt型になっていますが、[KotlinのInt型](https://kotlinlang.org/docs/reference/basic-types.html)が32ビットということで範囲外のようです。

> [32ビット - Wikipedia](https://ja.wikipedia.org/wiki/32%E3%83%93%E3%83%83%E3%83%88)
>32ビットアーキテクチャ 32ビットに格納できる符号なし整数の範囲は、0 から 4,294,967,295 である。 2の補数で表現できる符号付き整数は −2,147,483,648 から 2,147,483,647 を格納できる。

### KotlinのIntの最大値を調べてみる

[Int.MAX_VALUE](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/-m-a-x_-v-a-l-u-e.html)で調べることができます。

```maxint.kt
fun main(args: Array<String>) {
	println(Int.MAX_VALUE)
}
```

```
$ kotlinc ./maxint.kt -include-runtime -d maxint.jar
$ kotlin maxint.jar
2147483647
```

実行すると`2147483647`が最大値ということが分かります。

ブルゾンちえみ風に言うと **21億と4000万**ですね。

つまり35億はそのままでは扱えません。

ちなみに調べたら最初にあたった[こちらの記事](http://d.hatena.ne.jp/unsigned22/20080626/1214488735)でJavaだと`System.out.println(Integer.MAX_VALUE);`で調べられるとあったのでKotlinのコードの中にそのまま記載してみましたが、問題なく動いてました。

やはり歴史的にJavaは記事の文献がかなり多いので、検索ヒットしやすいです。
Javaで調べつつそのコードをKotlinで試すというのがやりやすいかもと思いました。
**Javaのコードがそのまま動くKotlinの利点**ですね。

```maxint.kt
fun main(args: Array<String>) {
    System.out.println(Integer.MAX_VALUE);
}
```

### Int型ではなくLong型を使う 

ということで[Long型](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)を利用します。

```35.kt
fun main(args: Array<String>) {
        var i: Long = 3500000000
        println(i)
}
```

```
$ kotlinc ./35.kt -include-runtime -d 35.jar
$ kotlin 35.jar

3500000000
```

ちゃんと35億が表示されました。

## 35億の剰余演算(%)

まだ剰余演算で課題があります。

```35.kt
fun main(args: Array<String>) {
    var input: Long = 3500000000
    val malePopulation: Long = 3500000000 //世界中の男

    if(input % malePopulation == 0){
        println("35億")
    }
}
```

```
35.kt:5:8: error: operator '==' cannot be applied to 'Long' and 'Int'
    if(input % malePopulation == 0){
       ^
```

この表記の場合0がIntと判定されてしまう模様です。

[`toLong()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/to-long.html)でキャストすることで回避できます。

```35.kt
fun main(args: Array<String>) {
    val input: Long = 3500000000
    val malePopulation: Long = 3500000000 //世界中の男

    if(input % malePopulation == 0.toLong()){
        println("35億")
    }
}
```

## 35億のときに`ブルゾンちえみ With B`するFizzBazz

改めて仕様です。

* 3で割り切れる時は"Fizz"
* 5で割り切れる時は"Bazz"
* 3でも5でも割り切れるときは"FizzBazz"
* 35億で割り切れる時は"With B"

```35fizzbazz.kt
fun main(args: Array<String>) {
    val malePopulation: Long = 3500000000 //世界中の男
	for (i in 1..malePopulation) {
        when {
            i % malePopulation == 0.toLong() -> println("With B")
            i % 15 == 0.toLong() -> println("FizzBuzz")
            i % 3 == 0.toLong() -> println("Fizz")
            i % 5 == 0.toLong() -> println("Buzz")
             else -> println(i)
        }
    }
}
```

さて実行ですが、 **35億ループを回すのでめっちゃ時間かかります。** 苦笑

何分くらいかかるのか執筆しながら検証中...

## FizzBazzを引数入力に対応させる

for文使うと処理時間的に大変なので、引数入力に対応させます。

`main()の引数args`で利用可能みたいです。

`kotlin hello.jar 35`など実行時に引数を指定すると`println(args[0])`で取得できます。

```35fizzbazz.kt
fun main(args: Array<String>) {
    println("input:" + args[0])
    val i: Long = args[0].toLong()
    val malePopulation: Long = 3500000000 //世界中の男
    
    when {
        i % malePopulation == 0.toLong() -> println("with B")
        i % 15 == 0.toLong() -> println("fizzbuzz")
        i % 3 == 0.toLong() -> println("fizz")
        i % 5 == 0.toLong() -> println("buzz")
        else -> println("特に無し")
    }
}
```

結果

```
$ kotlin 35fizzbazz.jar 2
input:2
特に無し

$ kotlin 35fizzbazz.jar 3
input:3
fizz

$ kotlin 35fizzbazz.jar 5
input:5
buzz

$ kotlin 35fizzbazz.jar 15
input:15
fizzbuzz

$ kotlin 35fizzbazz.jar 3500000000
input:3500000000
with B
```

お疲れ様でした。

## 所感

FizzBazzも桁数が増えるとハマりどころあるんですね。
Intだけでは出来ないってあたりに学びありだし、処理時間かかりすぎるので引数の取り方も覚えたし...あとJavaでの整数最大値の`Integer.MAX_VALUE`とJavaコードとKotlinの併用も

なんとなく思いついた35億ネタだけど35億はキャスト周りを教えるネタとしてはとっつきやすくてよいネタかもとか思ったりしました。笑