JavaScriptで数値の階乗の桁数を求める方法
問題
JavaScriptで、数値 num を唯一の引数として受け取る関数を作成することを考えます。
この関数は、num の階乗(n!)が何桁になるかを計算し、その桁数を返す必要があります。
たとえば、関数への入力が次のような場合を考えてみましょう。
入力
const num = 7;
出力
const output = 4;
出力の解説
7! = 5040 であり、5040は4桁の数字であるため、結果は 4 となります。
アプローチ:対数を使った賢い計算方法
一見すると、階乗を直接計算して文字列の長さを数えればよさそうに思えます。しかし、階乗は極めて急激に増加するため、少し大きな数でもすぐにJavaScriptの数値精度の限界を超えてしまいます。
そこで役立つのが対数の性質です。次の関係が成り立ちます。
log10(n!) = log10(n) + log10(n-1) + ... + log10(2)
また、正の整数 m の桁数は「⌊log10(m)⌋ + 1」で求められます。つまり、2から n までの各数値の常用対数を順番に足し合わせれば、階乗を実際に計算することなく桁数を導き出せるのです。
コード例
以下が実装コードです。
const num = 7;
const countDigits = (num = 1) => {
let res = 0;
while(num >= 2){
res += Math.log10(num);
num--;
};
return ~~res + 1;
}
console.log(countDigits(num));
出力
4
コードのポイント解説
- ループ条件が
num >= 2:log10(1) は 0 なので結果には影響しませんが、0以下になると log10 が -Infinity や NaN を返すため、2以上で止めるのが安全です。 ~~res(二重ビット否定):Math.floor()と同じように小数点以下を切り捨てます。記述が短く高速ですが、32ビット整数の範囲内でのみ正しく動作する点に注意してください。+ 1:桁数は「⌊log10(階乗)⌋ + 1」で表されるため、切り捨て後に1を加える必要があります。
この方法なら、階乗の値そのものを保持しないため、非常に大きな数に対してもオーバーフローを気にせず桁数だけを正確に求めることができます。
-
JavaScriptで数値の各桁の数字を一つずつ分割表示する方法
はじめに この記事では、ユーザーが入力した数値を検証し、有効な数値であればその各桁の数字を画面に一つずつ表示するJavaScriptプログラムの作り方を解説します。 動作イメージ ページ上のボタンをクリックすると入力ダイアログが開き、そこに数値を入力してOKを押すと、入力された数値の各桁が一行ずつ画面に出力される仕組みです。 例えば、入力が次のような場合—— 43354 画面には次のように表示されます。 4 3 3 5 4 完成コード HTML <!DOCTYPE html> <html> <head> &n
-
JavaScriptで単調増加する桁を持つ、指定した数以下の最大の数を求める方法
単調増加する桁(Monotonically Increasing Digits)とは 整数が「単調増加する桁」を持つとは、隣り合う任意の2つの桁 x と y の間に、常に x <= y が成り立つことを指します。たとえば 1234 や 2299 は左から右へ向かって桁が増加(または同じ)ため条件を満たしますが、332 のように「3 → 3 → 2」と減少が含まれる数は単調増加とはみなされません。 問題 今回求められているのは、数値 num を第一引数(かつ唯一の引数)として受け取るJavaScript関数を記述することです。 この関数は、num 以下の数の中から、単調増加する桁を持つ