Edited at

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


概要

Twitterを眺めていたら、「Sum of three cubes for 42 finally solved -- using real life planetary computer」という記事が引用されていました。

42といえば、なんとなく気になる数字ですよね。

使われている数字が大きいので、JavaScriptのBigIntの出番です。


BigIntとは

BigIntは、JavaScriptで任意の大きな整数を扱うことができるライブラリです。

(JavaScriptの標準の数値型であるNumberで信頼できる値として扱えるのは( 2 ^ 53 - 1)まで)

このエントリを書いている時点で、TC39(Ecma International, Technical Committee 39)でStage3です。

JavaScriptエンジンのV8では実装されたものがあり、Node V10 LTS以降で利用可能になっています。


コード

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

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


// 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

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

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)
})
})
})

実行してみます。

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で動かしておきます。設定は以下の通り。

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


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

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

// 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はこんな感じです。

const answer = require('./answer')

console.log("BigInt:" + answer.answer42())
console.log("Number:" + answer.answer42InNumber())

実行してみます。

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

冒頭に引用した記事によると、分散計算用のツール"Charity Engine"を使って50万台以上のPCの「空き時間」で計算したとのこと。