#javascript #arrays
#javascript #массивы
Вопрос:
Я использую массив для вычисления больших степеней 2. Массивы дополняют друг друга и послесловия, они вычисляют переносы и повторяют цикл n-1 раз, пока я не получу число в виде массива. Я делаю это для того, чтобы избежать ограничения в 15 цифр, которое имеет JavaScript.
Все работает нормально, как только я достигаю n = 42, где переносы начинают пропускаться, а числа не уменьшаются, что приводит к неправильным ответам.
Я попытался изменить метод, с помощью которого перенос обрабатывается внутри цикла while, с базового сложения на целочисленное деление и модуль Звучит глупо, но я добавил дополнительный цикл, чтобы проверить, не больше ли каких-либо элементов, чем 10, но он их не нашел.
for (var n = 1; n <= 100; n ) {
for (var i = 0, x = [2]; i < n - 1; i ) { // Loop for amount of times to multiply
x.unshift(0)
for (var j = x.length - 1; j > 0; j--) { // Double each element of the array
x[j] = x[j]
}
for (j = x.length - 1; x[j] > 0; j--) { // Check if element >= 10 and carry
while (x[j] >= 10) {
x[j - 1] = Math.floor(x[j] / 10)
x[j] = x[j] % 10
}
}
if (x[0] === 0) {
x.shift()
}
}
console.log('N: ' n ' Array: ' x)
}
Ожидаемые результаты заключаются в том, что каждый элемент в массиве будет сведен к одному числу и будет «перенесен» на элемент слева от него, например :
N: 1 Array: 2
N: 2 Array: 4
N: 3 Array: 8
N: 4 Array: 1,6
N: 5 Array: 3,2
N: 6 Array: 6,4
но начиная с n = 42, возникает ошибка, выглядящая следующим образом:
N: 42 Array: 4,2,18,18,0,4,6,5,1,1,1,0,4
N: 43 Array: 8,4,36,36,0,8,12,10,2,2,2,0,8
N: 44 Array: 1,7,5,9,2,1,8,6,0,4,4,4,1,6
N: 45 Array: 2,14,10,18,4,2,16,12,0,8,8,8,3,2
N: 46 Array: 7,0,3,6,8,7,4,4,1,7,7,6,6,4
N: 47 Array: 14,0,7,3,7,4,8,8,3,5,5,3,2,8
В чем ошибка, из-за которой это может быть вызвано подобным образом?
Комментарии:
1. Вам действительно следует подумать об использовании
BigInt
. Теперь у него есть встроенная поддержка за счет использования постфиксаn
для числовых литералов.2. Даже не знал, что это существует. Спасибо
3. хотя вам следует использовать BigInt, начиная с вашего алгоритма, не следует ли вам проверять во внутреннем цикле for
j > 0
вместоx[j] > 0
? (строка 8)4. Вы также всегда можете попытаться выполнить отладку. Код слишком (чрезмерно) сложный, чтобы я мог просто понять и просмотреть его в голове для получения больших чисел. Отлаживая его, вы должны обнаружить проблему за секунду, но в любом случае должен быть лучший способ вычислить это без использования списков.
Ответ №1:
Я думаю, причина, по которой ваш код не работает, заключается в этой строке, for (j = x.length - 1; x[j] > 0; j--) { // Check if element >= 10 and carry
которую вы не хотите проверять, x[j] > 0
но j > 0
.
Также ваш второй цикл: for (var i = 0, x = [2]; i < n - 1; i ) {
— вам это не нужно, нет причин пересчитывать все на каждой итерации, вы можете использовать предыдущий результат.
Вы также можете удваивать значения таким образом: x = x.map(n => n * 2)
(мне кажется, это немного более шаблонно).
И в этом нет необходимости, x[j - 1] = Math.floor(x[j] / 10)
это может быть просто x[j - 1] = 1
, поскольку предыдущие числа до 9, удвоенные, они не более 18, так что 1 — единственный случай, если x[j] >= 10
.
Может быть код:
let x = [2] // starting point
for (var n = 1; n <= 100; n ) {
x = [0, ...x].map(n => n * 2)
for (j = x.length - 1; j > 0; j--) {
if (x[j] >= 10) {
x[j - 1] = 1
x[j] %= 10
}
}
if (x[0] === 0) {
x = x.slice(1)
}
console.log('N: ' n ' Array: ' x)
}
Ответ №2:
Если все, что вам нужно, это большие степени 2, почему вы проходите через безумную проблему использования списков для вычисления этого? Разве это не то же самое:
function BigPow2(x, acc=2.0) {
//document.writeln(acc);
acc = acc >= 5 ? acc / 5 : acc * 2;
return x <= 1 ? acc : BigPow2(x-1, acc);
}
Или, в качестве альтернативы, использовать BigInt?