(ネタ) x ^ 3 + y ^ 3 + z ^ 3 = 42 の答えを見つけたチームがいるらしいのでJSのBigIntで確かめてみる

# 概要

Twitterを眺めていたら、「[Sum of three cubes for 42 finally solved -- using real life planetary computer](
https://www.sciencedaily.com/releases/2019/09/190906134011.htm)」という記事が引用されていました。

[42](https://ja.wikipedia.org/wiki/%E7%94%9F%E5%91%BD%E3%80%81%E5%AE%87%E5%AE%99%E3%80%81%E3%81%9D%E3%81%97%E3%81%A6%E4%B8%87%E7%89%A9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AE%E7%A9%B6%E6%A5%B5%E3%81%AE%E7%96%91%E5%95%8F%E3%81%AE%E7%AD%94%E3%81%88)といえば、なんとなく気になる数字ですよね。

使われている数字が大きいので、JavaScriptの[BigInt](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/BigInt)の出番です。

# BigIntとは

BigIntは、JavaScriptで任意の大きな整数を扱うことができるライブラリです。
(JavaScriptの標準の数値型であるNumberで信頼できる値として扱えるのは（ 2 ^ 53 - 1）まで)

このエントリを書いている時点で、TC39(Ecma International, Technical Committee 39)で[Stage3](https://github.com/tc39/proposal-bigint)です。

JavaScriptエンジンの[V8では実装](https://v8.dev/blog/bigint)されたものがあり、Node V10 LTS以降で利用可能になっています。

# コード

GitHubに置いてあります。[https://github.com/hrkt/answer42/releases/tag/1.0.0](https://github.com/hrkt/answer42/releases/tag/1.0.0)

BigIntを使うときは、BigInt(数値)としてオブジェクトを初期化するほかに、末尾に「n」をつけてBigIntであることを示すことができます。

```javascript

// using BigInt(https://developer.mozilla.org/ja/docs/Web/JavaScript

exports.answer42 = function() {
    const x = -80538738812075974n
    const y = 80435758145817515n
    const z = 12602123297335631n
    return  x ** 3n + y ** 3n + z ** 3n
}
```

補足: 3乗を示している「\*\*3n」 には、BigIntであることを示す「n」が必要です。BigIntとNumberの演算は、暗黙の裡に型変換されることがないため、下記のようなエラーとなります。。

```
    return  x ** 3 + y ** 3 + z ** 3
              ^

TypeError: Cannot mix BigInt and other types, use explicit conversions
```


テストしてみます。テストコードは下記です。

```javascript
const assert = require('assert')
const answer = require("../answer")
describe('The answer', function() {
  describe('#answer42()', function() {
    it('should return 42', function() {
      assert.equal(answer.answer42(), 42n)
    })
  })
})
```

実行してみます。

```console
PS C:\Users\work\answer42\js> npm run test 
> answer42@1.0.0 test C:\Users\work\answer42\js
> mocha



  The answer
    #answer42()
      √ should return 42


  1 passing (232ms)
```

答えがあっています。

テストは、これをGitHub Actionsで動かしておきます。設定は以下の通り。

```yml
name: Node CI

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [10.x, 12.x]

    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - name: npm install, build, and test
      run: |
        (cd js; npm install)
        (cd js; npm run test)
      env:
        CI: true
```

![Node_ci_passing.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65002/00b9a8b4-fd06-6018-e493-7b74c18f24b5.png)



# 補足：Numberで計算した場合との違い

BigIntを使わず、下記のようにNumberで実行した場合と比べてみます。

```javascript
// using Number(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number)
exports.answer42InNumber = function() {
    const x = -80538738812075974
    const y = 80435758145817515
    const z = 12602123297335631
    return  x ** 3 + y ** 3 + z ** 3
}

```

main.jsはこんな感じです。

```javascript
const answer = require('./answer')
console.log("BigInt:" + answer.answer42())
console.log("Number:" + answer.answer42InNumber())
```

実行してみます。

```console
PS C:\Users\work\answer42\js> npm run start

> answer42@1.0.0 start C:\Users\work\answer42\js
> node main.js

BigInt:42
Number:1.989298733926156e+35
```

Numberだと、~~生命、宇宙、そして万物についての究極の疑問の答え~~42とならないことがわかります。


# まとめ

JavaScriptのBigIntを使い、大きな数を扱うときの例を扱いました。

## 補足

Wolfram Alpha様であれば実は一瞬で解けたりするのか、と思ってためしてみましたが、そんなことはありませんでした。

[https://www.wolframalpha.com/input/?i=x+%5E+3+%2B+y+%5E+3+%2B+z+%5E+3+%3D+42](https://www.wolframalpha.com/input/?i=x+%5E+3+%2B+y+%5E+3+%2B+z+%5E+3+%3D+42)

冒頭に引用した記事によると、[分散計算用のツール"Charity Engine"](https://www.charityengine.com/grid)を使って50万台以上のPCの「空き時間」で計算したとのこと。