JavaScript: недостаточно памяти для огромного массива результатов в реализации Sieve of Atkin - PullRequest
0 голосов
/ 16 июня 2019

В настоящее время я запускаю несколько тестов между JavaScript, asm.js и WebAssembly.Для этого я реализовал небольшую программу, которая ищет простые числа с помощью алгоритма Sieve of Atkin.

Чтобы сделать нарастание незначительным, я вычисляю простые числа до 500'000'000.Моя проблема в том, что реализации JavaScript не хватает памяти, потому что массив результатов становится огромным.Error message

Это моя текущая реализация:

const AMOUNT = 500000000;

function getPrimes() {
  const limit = AMOUNT;
  const width = Math.sqrt(limit);
  let i, j, x, y, z;
  let primes = new Array(limit);

  const begin = performance.now();
  for (x = 1; x <= width; x++) {
    for (y = 1; y <= width; y++) {
      z = 4 * x * x + y * y;
      if (z < limit && (z % 60 == 1 || z % 60 == 13 || z % 60 == 17 || z
          % 60 == 29 || z % 60 == 37 || z % 60 == 41 || z % 60 == 49
          || z % 60 == 53)) {
        primes[z] = !primes[z];
      }

      z = 3 * x * x + y * y;
      if (z < limit && (z % 60 == 7 || z % 60 == 19 || z % 60 == 31 || z
          % 60 == 43)) {
        primes[z] = !primes[z];
      }

      z = 3 * x * x - y * y;
      if (x > y && z < limit && (z % 60 == 11 || z % 60 == 23 || z % 60
          == 47 || z % 60 == 59)) {
        primes[z] = !primes[z];
      }
    }
  }

  const end = performance.now();

  let last_prime = 0;
  for (i = limit; i >= 0; i--) {
    if(primes[i] == 1) {
      last_prime = i;
      break;
    }
  }

  primes = null;
  time_spent = end - begin;
  console.log(time_spent/1000 + ', ' + last_prime);
}

document.addEventListener("DOMContentLoaded", function() {
  let i;
  for (i = 0; i <= 10; i++) {
    getPrimes();
  }
});

Это мой HTML-код для его запуска:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Find Primes</title>
    <script src="./find-primes.js"></script>
  </head>
  <body>
    Check the console.
  </body>
</html>

Что ядо сих пор пробовал: - Убедитесь, что массив primes собирается после каждого запуска, обнуляя его.- Выделите весь массив один раз.

У вас есть больше идей по оптимизации использования памяти моей реализацией JavaScript?

Что я пытаюсь предотвратить, так это разбить массив или вычислить результатв разных итерациях, потому что я хочу сравнить исходную производительность вычислений.Не должно быть никакого влияния управления памятью на тест.

Я использую:

  • Google Chrome: версия 75.0.3770.90 (Официальная сборка) (64-разрядная версия)
  • Mozilla Firefox: версия 67.0.2 (64-разрядная версия)

Заранее спасибо!

1 Ответ

3 голосов
/ 16 июня 2019

Вместо Array, который наивно хранит каждый из ваших флагов как double (и, вероятно, имеет еще больше накладных расходов памяти для своей способности хранить произвольные смешанные типы), вы можете использовать Uint8Array или другой целочисленный формат без знака, который уменьшит использование вашей памяти как минимум в 64 раза.

Вам нужно будет изменить способ инициализации, переключения и проверки флагов.

Инициализация:

const BitArray = Uint8Array; // or Uint16Array, Uint32Array
const BITS_PER_ELEMENT = BitArray.BYTES_PER_ELEMENT * 8;
const BIT_SHIFT = Math.log2(BITS_PER_ELEMENT);
const BIT_MASK = BITS_PER_ELEMENT - 1;
let primes = new BitArray(Math.ceil(limit / BITS_PER_ELEMENT));

Переключение:

primes[z >> BIT_SHIFT] ^= 1 << (z & BIT_MASK);

Проверка:

if (primes[i >> BIT_SHIFT] & (1 << (i & BIT_MASK)))

Любой выбор между Uint8Array, Uint16Array и Uint32Array будет использовать тот же объем памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...