JavaScriptで10進数を階乗進数(ファクトリアルベース)に変換する方法
階乗進数(ファクトリアルベース)とは?
階乗進数(factorial number system)は、各桁の重みを「数の冪」ではなく「階乗」にとるユニークな記数法です。通常のN進法では桁の重みが一定ですが、階乗進数では桁ごとに取りうる値の範囲が異なるのが最大の特徴です。
- 最下位の桁(0番目):常に 0(基数 0!)
- 下から2番目の桁:0 または 1(基数 1!)
- 下から3番目の桁:0・1・2 のいずれか(基数 2!)
一般化すると、下から n 番目の桁は必ず 0 ~ n の値をとり、その重みは n! になります。
問題:10進数と階乗進数を相互変換する
今回実装するのは、次の2つの関数です。
- decimalToFact:10進数を受け取り、階乗進数表現の文字列を返す
- factToDecimal:階乗進数表現の文字列を受け取り、10進数に復元する
具体例:463 は「341010」にエンコードされる
たとえば10進数の 463 は、次のように分解できるため「341010」と表されます。
463 = 3×5! + 4×4! + 1×3! + 0×2! + 1×1! + 0×0!
実際に計算すると、3×120 + 4×24 + 1×6 + 0×2 + 1×1 + 0×1 = 360+96+6+1=463 となり、元の数値と一致します。
JavaScriptによる実装コード
以下が実際のコードです。桁の値が10を超える場合に備え、数字とアルファベットを連結した凡例文字列(legend)を用意しています。
const num = 463;
// 10進数 → 階乗進数 へ変換する関数
const decimalToFact = (num = 1) => {
const legend = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
let str = '0';
let i = 2;
while(num){
str = legend[num%i] + str;
num = Math.floor(num / i);
i++;
};
return str;
};
// 階乗進数 → 10進数 へ戻す関数(ホーナー法)
const factToDecimal = (str = '') => {
const legend = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const l = str.length;
return str
.split('')
.reduce((a,e,i) => Number(a) * (l - i) + legend.indexOf(e), 0);
};
const fact = decimalToFact(num);
const dec = factToDecimal(fact);
console.log(fact);
console.log(dec);コードのポイント
- decimalToFact:除算の基数を 2 から順に 1 ずつ増やしながら剰余を求め、それを文字列の左側に追加していくことで階乗進数の桁を組み立てます。初期値を
'0'にしておくことで、常に 0 番目の桁(最下位)が 0 になる規則を満たします。 - factToDecimal:ホーナー法(Horner's method)を利用し、左の桁から順に「これまでの累計 × 次の基数 + 現在の桁」を繰り返すことで、効率よく元の10進数を復元します。
- legend配列:10以上の値を持つ桁を A, B, C… として表現できるため、大きな数にも対応可能です。
出力結果
コンソールには次のように出力されます。
341010 463
463 をエンコードすると「341010」になり、それを再度デコードすると元の 463 に正しく戻っていることが確認できます。
まとめ
階乗進数は一見特殊な記数法ですが、「n番目の桁の基数が n+1 になる」というシンプルな規則に従っています。剰余演算と除算を組み合わせたエンコード、ホーナー法によるデコードという定石を押さえれば、JavaScriptでも簡潔に相互変換を実装できます。順列生成や組み合わせのインデックス管理など、応用先も広いので覚えておくと役立ちます。
-
JavaScriptのconst宣言とは?再代入できない変数の基本と使い方を解説
JavaScriptのconst宣言は、値を再代入することも後から再宣言することもできない変数を作成するための構文です。constはES2015(ES6)で導入されました。 const宣言の主な特徴 一度値を代入すると、別の値に再代入することはできません。 同じ名前の変数を同じスコープ内で再宣言するとエラーになります。 宣言時に必ず初期値を代入する必要があります。 ブロックスコープ({}内でのみ有効)を持ちます。 それでは、JavaScriptにおけるconst宣言の実際のコードを見ていきましょう。 サンプルコード <!DOCTYPE html> <html>
-
JavaScriptのconstとletの違いを徹底解説!ブロックスコープ変数の基本と使い方
JavaScriptにおけるconstとletの基本const と let は、ES2015(ES6)で導入された変数宣言用のキーワードです。どちらもブロックスコープ(波括弧 { } で囲まれた範囲)に対応しているのが特徴で、関数スコープしか持たなかった従来の var とは異なる挙動を示します。両者の大きな違いは再代入の可否です。letで宣言した変数は後から何度でも値を再代入できますが、constで宣言した変数は再代入しようとするとエラー(TypeError)が発生します。letとconstの主な違い項目letconst再代入可能不可(エラー発生)スコープブロックスコープブロックスコープ宣言時