Генерация случайных чисел в java

yield – дорога в обе стороны

До этого генераторы наиболее напоминали «итераторы на стероидах». Но, как мы сейчас увидим, это не так, есть фундаментальное различие, генераторы гораздо мощнее и гибче.

Всё дело в том, что – дорога в обе стороны: он не только возвращает результат наружу, но и может передавать значение извне в генератор.

Вызов делает следующее:

  • Возвращает во внешний код, приостанавливая выполнение генератора.
  • Внешний код может обработать значение, и затем вызвать с аргументом: .
  • Генератор продолжит выполнение, аргумент будет возвращён как результат (и записан в ).

Продемонстрируем это на примере:

На рисунке ниже прямоугольником изображён генератор, а вокруг него – «внешний код», который с ним взаимодействует:

На этой иллюстрации показано то, что происходит в генераторе:

  1. Первый вызов – всегда без аргумента, он начинает выполнение и возвращает результат первого («2+2?»). На этой точке генератор приостанавливает выполнение.
  2. Результат переходит во внешний код (в ). Внешний код может выполнять любые асинхронные задачи, генератор стоит «на паузе».
  3. Когда асинхронные задачи готовы, внешний код вызывает с аргументом. Выполнение генератора возобновляется, а выходит из присваивания как результат .

В примере выше – только два .

Увеличим их количество, чтобы стал более понятен общий поток выполнения:

Взаимодействие с внешним кодом:

  1. Первый начинает выполнение… Оно доходит до первого .
  2. Результат возвращается во внешний код.
  3. Второй передаёт обратно в генератор как результат первого и возобновляет выполнение.
  4. …Оно доходит до второго , который станет результатом .
  5. Третий передаёт в генератор как результат второго и возобновляет выполнение, которое завершается окончанием функции, так что .

Получается «пинг-понг»: каждый передаёт в генератор значение, которое становится результатом текущего , возобновляет выполнение и получает выражение из следующего . Исключением является первый вызов , который не может передать значение в генератор, т.к. ещё не было ни одного .

Способы записи числа

Представьте, что нам надо записать число 1 миллиард. Самый очевидный путь:

Но в реальной жизни мы обычно опускаем запись множества нулей, так как можно легко ошибиться. Укороченная запись может выглядеть как или для 7 миллиардов 300 миллионов. Такой принцип работает для всех больших чисел.

В JavaScript можно использовать букву , чтобы укоротить запись числа. Она добавляется к числу и заменяет указанное количество нулей:

Другими словами, производит операцию умножения числа на 1 с указанным количеством нулей.

Сейчас давайте запишем что-нибудь очень маленькое. К примеру, 1 микросекунду (одна миллионная секунды):

Записать микросекунду в укороченном виде нам поможет .

Если мы подсчитаем количество нулей , их будет 6. Естественно, верная запись .

Другими словами, отрицательное число после подразумевает деление на 1 с указанным количеством нулей:

Шестнадцатеричные числа широко используются в JavaScript для представления цветов, кодировки символов и многого другого. Естественно, есть короткий стиль записи: , после которого указывается число.

Например:

Не так часто используются двоичные и восьмеричные числа, но они также поддерживаются для двоичных и для восьмеричных:

Есть только 3 системы счисления с такой поддержкой. Для других систем счисления мы рекомендуем использовать функцию (рассмотрим позже в этой главе).

Пример использования

Базовое использование

В следующем примере с помощью метода random() мы получим случайное число от 0 (включительно) до 1 (не включая):

const rnd = Math.random();
console.log(rnd); // возвращаемое значение 0.5017845092137254

Получение случайного числа в заданном диапазоне

В следующем примере с помощью метода random() мы рассмотрим как получить случайное число внутри определенного диапазона

Обратите внимание, что возвращаемое значение не может быть меньше параметра min и не более, или равно параметра max:

function getRandomFromRange(min, max) {
  return Math.random() * (max - min) + min;
}

console.log(getRandomFromRange(5, 10)); // возвращаемое значение 6.830906542874363
console.log(getRandomFromRange(5, 10)); // возвращаемое значение 9.436449613234068
console.log(getRandomFromRange(5, 10)); // возвращаемое значение 6.4493344451274055
console.log(getRandomFromRange(5, 10)); // возвращаемое значение 5.160973635403946
console.log(getRandomFromRange(5, 10)); // возвращаемое значение 5.369261822513969

Получение случайного целого числа в заданном диапазоне

В следующем примере мы рассмотрим как с помощью метода random(), ceil() и floor() объекта Math получить случайное целое число внутри определенного диапазона

Обратите внимание, что возвращаемое значение не может быть меньше параметра min и не более, или равно параметра max:

function getRandomIntFromRange(min, max) {
  min = Math.ceil(min); // вычисляет и возвращает наименьшее целое число, которое больше или равно переданному числу (округляет число вверх)
  max = Math.floor(max); // вычисляет и возвращает наибольшее целое число, которое меньше или равно переданному числу (округляет число вниз)
  return Math.floor(Math.random() * (max - min)) + min; 
}

console.log(getRandomIntFromRange(5, 10)); // возвращаемое значение 6
console.log(getRandomIntFromRange(5, 10)); // возвращаемое значение 9
console.log(getRandomIntFromRange(5, 10)); // возвращаемое значение 1
console.log(getRandomIntFromRange(5, 10)); // возвращаемое значение 5
console.log(getRandomIntFromRange(5, 10)); // возвращаемое значение 6

Получение случайного элемента в массиве

В следующем примере мы рассмотрим как с помощью методов ceil() и random() найти случайный элемент внутри массива:

const arr = ;

const randomElement = arr[Math.floor(Math.random() * arr.length)];

Например:
arr; // индекс будет соответствовать 2

JavaScript Math

Генератор псевдослучайных чисел и генератор случайных чисел

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

Этот источник используется для накопления энтропии с последующим получением из неё начального значения (initial value, seed), которое необходимо генераторам случайных чисел (ГСЧ) для формирования случайных чисел.

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

Выходит, что чтобы создать псевдослучайную последовательность нам нужен алгоритм, который будет генерить некоторую последовательность на основании определенной формулы. Но такую последовательность можно будет предсказать. Тем не менее, давайте пофантазируем, как бы могли написать свой генератор случайных чисел, если бы у нас не было Math.random()

ГПСЧ имеет некоторый алгоритм, который можно воспроизвести.
ГСЧ — это получение чисел полностью из какого либо шума, возможность просчитать который стремится к нулю. При этом в ГСЧ есть определенные алгоритмы для выравнивания распределения.

JavaScript

JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()

JS Boolean
constructor
prototype
toString()
valueOf()

JS Classes
constructor()
extends
static
super

JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()

JS Error
name
message

JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()

JS JSON
parse()
stringify()

JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
clz32()
cos()
cosh()
E
exp()
expm1()
floor()
fround()
LN2
LN10
log()
log10()
log1p()
log2()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sign()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()

JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()

JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()

(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx

JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while

JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()

generator.throw

Как мы видели в примерах выше, внешний код может передавать значение в генератор как результат .

…Но можно передать не только результат, но и инициировать ошибку. Это естественно, так как ошибка является своего рода результатом.

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

Например, здесь приведёт к ошибке:

Ошибка, которая проброшена в генератор на строке , приводит к исключению на строке с . В примере выше перехватывает её и отображает.

Если мы не хотим перехватывать её, то она, как и любое обычное исключение, «вывалится» из генератора во внешний код.

Текущая строка вызывающего кода – это строка с , отмечена . Таким образом, мы можем отловить её во внешнем коде, как здесь:

Если же ошибка и там не перехвачена, то дальше – как обычно, она выпадает наружу и, если не перехвачена, «повалит» скрипт.

Придумываем свой алгоритм ГПСЧ

Мы можем взять последовательность каких-то чисел и брать от них модуль числа. Самый простой пример, который приходит в голову. Нам нужно подумать, какую последовательность взять и модуль от чего. Если просто в лоб от 0 до N и модуль 2, то получится генератор 1 и 0:

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

А что если взять какую-то известную, но нелинейную последовательность, например число PI. А в качестве значения для модуля будем брать не 2, а что-то другое. Можно даже подумать на тему меняющегося значения модуля. Последовательность цифр в числе Pi считается случайной. Генератор может работать, используя числа Пи, начиная с какой-то неизвестной точки. Пример такого алгоритма, с последовательностью на базе PI и с изменяемым модулем:

Но в JS число PI можно вывести только до 48 знака и не более. Поэтому предсказать такую последовательность все так же легко и каждый запуск такого генератора будет выдавать всегда одни и те же числа. Но наш генератор уже стал показывать числа от 0 до 9.

Мы получили генератор чисел от 0 до 9, но распределение очень неравномерное и каждый раз он будет генерировать одну и ту же последовательность.

Мы можем взять не число Pi, а время в числовом представлении и это число рассматривать как последовательность цифр, причем для того, чтобы каждый раз последовательность не повторялась, мы будем считывать ее с конца. Итого наш алгоритм нашего ГПСЧ будет выглядеть так:

Вот это уже похоже на генератор псевдослучайных чисел. И тот же Math.random() — это ГПСЧ, про него мы поговорим чуть позже. При этом у нас каждый раз первое число получается разным.

Собственно на этих простых примерах можно понять как работают более сложные генераторы случайных числе. И есть даже готовые алгоритмы. Для примера разберем один из них — это Линейный конгруэнтный ГПСЧ(LCPRNG).

Плоский асинхронный код

Одна из основных областей применения генераторов – написание «плоского» асинхронного кода.

Общий принцип такой:

  • Генератор не просто значения, а промисы.
  • Есть специальная «функция-чернорабочий» которая запускает генератор, последовательными вызовами получает из него промисы – один за другим, и, когда очередной промис выполнится, возвращает его результат в генератор следующим .
  • Последнее значение генератора () уже обрабатывает как окончательный результат – например, возвращает через промис куда-то ещё, во внешний код или просто использует, как в примере ниже.

Напишем такой код для получения аватара пользователя с github и его вывода, аналогичный рассмотренному в статье про промисы.

Для AJAX-запросов будем использовать метод fetch, он как раз возвращает промисы.

Функция в примере выше – универсальная, она может работать с любым генератором, который промисы.

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

Одна из самых известных – это библиотека co, которую мы рассмотрим далее.

Focusrite Scarlett 2i2 2nd Generation

Выбор внешней звуковой карты для небольшой домашней студии был бы неполным без модели второго поколения от Focusrite. Это устройство имеет металлический корпус, под которым расположены новейшие микрофонные конверторы и усилители. При минимальной задержке передачи сигнала карта поддерживает дискретизацию звука на частоте 192 кГц.

Изделие выглядит симпатично, регуляторы на передней панели имеют рифление, упрощающее тонкую настройку звучания, которое и без того отличается высокой чистотой и качеством.

Преобразователи характеризуются динамическим диапазоном на уровне 110 дБ, временная задержка – порядка 2.75 мс, позволяя работать с устройством фактически в режиме реального времени, это касается и воспроизведения, и записи, и мониторинга.

Имеется встроенная защита аналоговых схем от нестабильного напряжения. Фирменный пакет ПО Focusrite Creative Pack включает, кроме основного функционала, 12 дополнительных плагинов.

Преимущества модели:

  • компактные габариты;
  • качественная запись звука;
  • минимальная временная задержка;
  • отсутствие шумов при записи звука.

Как отмечают некоторые пользователи, карта иногда подвисает, но случается это нечасто.

API

  • : Utilizes
  • : Utilizes
  • : Utilizes
  • : Produces a new Mersenne Twister. Must be seeded before use.

Or you can make your own!

interfaceEngine{next()number;}

Any object that fulfills that interface is an .

  • : Seed the twister with an initial 32-bit integer.
  • : Seed the twister with an array of 32-bit integers.
  • : Seed the twister with automatic information. This uses the current Date and other entropy sources.
  • : Produce a 32-bit signed integer.
  • : Discard random values. More efficient than running repeatedly.
  • : Return the number of times the engine has been used plus the number of discarded values.

One can seed a Mersenne Twister with the same value () or values () and discard the number of uses () to achieve the exact same state.

If you wish to know the initial seed of , it is recommended to use the function to create the seed manually (this is what does under-the-hood).

constseed=createEntropy();constmt=MersenneTwister19937.seedWithArray(seed);useTwisterALot(mt);constclone=MersenneTwister19937.seedWithArray(seed).discard(mt.getUseCount());

Random.js also provides a set of methods for producing useful data from an engine.

  • : Produce an integer within the inclusive range . can be at its minimum -9007199254740992 (-2 ** 53). can be at its maximum 9007199254740992 (2 ** 53).
  • : Produce a floating point number within the range . Uses 53 bits of randomness.
  • : Produce a boolean with a 50% chance of it being .
  • : Produce a boolean with the specified chance causing it to be .
  • : Produce a boolean with / chance of it being true.
  • : Return a random value within the provided within the sliced bounds of and .
  • : Same as .
  • : Shuffle the provided (in-place). Similar to .
  • : From the array, produce an array with elements that are randomly chosen without repeats.
  • : Same as
  • : Produce an array of length with as many rolls.
  • : Produce a random string using numbers, uppercase and lowercase letters, , and of length .
  • : Produce a random string using the provided string as the possible characters to choose from of length .
  • or : Produce a random string comprised of numbers or the characters of length .
  • : Produce a random string comprised of numbers or the characters of length .
  • : Produce a random within the inclusive range of . and must both be s.

An example of using would be as such:

constengine=MersenneTwister19937.autoSeed();constdistribution=integer(,99);functiongenerateNaturalLessThan100(){returndistribution(engine);}

Producing a distribution should be considered a cheap operation, but producing a new Mersenne Twister can be expensive.

An example of producing a random SHA1 hash:

var engine = nativeMath;var distribution =hex(false);functiongenerateSHA1(){returndistribution(engine,40);}

Why is this needed?

Despite being capable of producing numbers within [0, 1), there are a few downsides to doing so:

  • It is inconsistent between engines as to how many bits of randomness:
    • Internet Explorer: 53 bits
    • Mozilla Firefox: 53 bits
    • Google Chrome/node.js: 32 bits
    • Apple Safari: 32 bits
  • It is non-deterministic, which means you can’t replay results consistently
  • In older browsers, there can be manipulation through cross-frame random polling. This is mostly fixed in newer browsers and is required to be fixed in ECMAScript 6.

Also, and most crucially, most developers tend to use improper and biased logic as to generating integers within a uniform distribution.

Extending

You can add your own methods to instances, as such:

var random =newRandom();random.bark=function(){if(this.bool()){return"arf!";}else{return"woof!";}};random.bark();

This is the recommended approach, especially if you only use one instance of .

Or you could even make your own subclass of Random:

functionMyRandom(engine){returnRandom.call(this, engine);}MyRandom.prototype=Object.create(Random.prototype);MyRandom.prototype.constructor= MyRandom;MyRandom.prototype.mood=function(){switch(this.integer(,2)){casereturn"Happy";case1return"Content";case2return"Sad";}};var random =newMyRandom();random.mood();

Or, if you have a build tool are are in an ES6+ environment:

classMyRandomextendsRandom{mood(){switch(this.integer(,2)){casereturn"Happy";case1return"Content";case2return"Sad";}}}constrandom=newMyRandom();random.mood();

Extending

You can add your own methods to instances, as such:

var random = new Random();
random.bark = function() {
  if (this.bool()) {
    return "arf!";
  } else {
    return "woof!";
  }
};
random.bark(); //=> "arf!" or "woof!"

This is the recommended approach, especially if you only use one instance of .

Or you could even make your own subclass of Random:

function MyRandom(engine) {
  return Random.call(this, engine);
}
MyRandom.prototype = Object.create(Random.prototype);
MyRandom.prototype.constructor = MyRandom;
MyRandom.prototype.mood = function() {
  switch (this.integer(, 2)) {
    case :
      return "Happy";
    case 1:
      return "Content";
    case 2:
      return "Sad";
  }
};
var random = new MyRandom();
random.mood(); //=> "Happy", "Content", or "Sad"

Or, if you have a build tool are are in an ES6+ environment:

class MyRandom extends Random {
  mood() {
    switch (this.integer(, 2)) {
      case :
        return "Happy";
      case 1:
        return "Content";
      case 2:
        return "Sad";
    }
  }
}
const random = new MyRandom();
random.mood(); //=> "Happy", "Content", or "Sad"

Alternate API

There is an alternate API which may be easier to use, but may be less performant. In scenarios where performance is paramount, it is recommended to use the aforementioned API.

constrandom=newRandom(MersenneTwister19937.seedWithArray(0x12345678,0x90abcdef));constvalue=r.integer(,99);constotherRandom=newRandom();

This abstracts the concepts of engines and distributions.

  • : Produce an integer within the inclusive range . can be at its minimum -9007199254740992 (2 ** 53). can be at its maximum 9007199254740992 (2 ** 53). The special number is never returned.
  • : Produce a floating point number within the range . Uses 53 bits of randomness.
  • : Produce a boolean with a 50% chance of it being .
  • : Produce a boolean with the specified chance causing it to be .
  • : Produce a boolean with / chance of it being true.
  • : Return a random value within the provided within the sliced bounds of and .
  • : Shuffle the provided (in-place). Similar to .
  • : From the array, produce an array with elements that are randomly chosen without repeats.
  • : Same as
  • : Produce an array of length with as many rolls.
  • : Produce a random string using numbers, uppercase and lowercase letters, , and of length .
  • : Produce a random string using the provided string as the possible characters to choose from of length .
  • or : Produce a random string comprised of numbers or the characters of length .
  • : Produce a random string comprised of numbers or the characters of length .
  • : Produce a random within the inclusive range of . and must both be s.

Usage

node.js

In your project, run the following command:

npm install random-js

or

yarn add random-js

In your code:

// ES6 Modules
import { Random } from "random-js";
const random = new Random(); // uses the nativeMath engine
const value = random.integer(1, 100);
// CommonJS Modules
const { Random } = require("random-js");
const random = new Random(); // uses the nativeMath engine
const value = random.integer(1, 100);

Or to have more control:

const Random = require("random-js").Random;
const random = new Random(MersenneTwister19937.autoSeed());
const value = random.integer(1, 100);

It is recommended to create one shared engine and/or instance per-process rather than one per file.

Browser using AMD or RequireJS

Download and place it in your project, then use one of the following patterns:

define(function(require) {
  var Random = require("random");
  return new Random.Random(Random.MersenneTwister19937.autoSeed());
});

define(function(require) {
  var Random = require("random");
  return new Random.Random();
});

define("random", function(Random) {
  return new Random.Random(Random.MersenneTwister19937.autoSeed());
});

Browser using tag

Download and place it in your project, then add it as a tag as such:

<script src="lib/random-js.min.js"></script>
<script>
  // Random is now available as a global (on the window object)
  var random = new Random.Random();
  alert("Random value from 1 to 100: " + random.integer(1, 100));
</script>

Генератор – итератор

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

Его можно перебирать и через :

Заметим, однако, существенную особенность такого перебора!

При запуске примера выше будет выведено значение , затем . Значение выведено не будет. Это потому что стандартный перебор итератора игнорирует на последнем значении, при . Так что результат в цикле не выводится.

Соответственно, если мы хотим, чтобы все значения возвращались при переборе через , то надо возвращать их через :

…А зачем вообще при таком раскладе, если его результат игнорируется? Он тоже нужен, но в других ситуациях. Перебор через – в некотором смысле «исключение». Как мы увидим дальше, в других контекстах очень даже востребован.

1 Псевдослучайные числа

Иногда программист сталкивается с простыми, казалось бы, задачами: «отобрать случайный фильм для вечернего просмотра из определенного списка», «выбрать победителя лотереи», «перемешать список песен при тряске смартфона», «выбрать случайное число для шифрования сообщения», и каждый раз у него возникает очень закономерный вопрос: а как получить это самое случайное число?

Вообще-то, если вам нужно получить «настоящее случайное число», сделать это довольно-таки трудно. Вплоть до того, что в компьютер встраивают специальные математические сопроцессоры, которые умеют генерировать такие числа, с выполнением всех требований к «истинной случайности».

Поэтому программисты придумали свое решение — псевдослучайные числа. Псевдослучайные числа — это некая последовательность, числа в которой на первый взгляд кажутся случайными, но специалист при детальном анализе сможет найти в них определенные закономерности. Для шифрования секретных документов такие числа не подойдут, а для имитации бросания кубика в игре — вполне.

Есть много алгоритмов генерации последовательности псевдослучайных чисел и почти все из них генерируют следующее случайное число на основе предыдущего и еще каких-то вспомогательных чисел.

Например, данная программа выведет на экран неповторяющихся чисел:

Кстати, мы говорим не о псевдослучайных числах, а именно о последовательности таких чисел. Т.к. глядя на одно число невозможно понять, случайное оно или нет.

Случайное число ведь можно получить разными способами:

Проверка: isFinite и isNaN

Помните эти специальные числовые значения?

  • (и ) — особенное численное значение, которое ведёт себя в точности как математическая бесконечность ∞.
  • представляет ошибку.

Эти числовые значения принадлежат типу , но они не являются «обычными» числами, поэтому есть функции для их проверки:

  • преобразует значение в число и проверяет является ли оно :

    Нужна ли нам эта функция? Разве не можем ли мы просто сравнить ? К сожалению, нет. Значение уникально тем, что оно не является равным ни чему другому, даже самому себе:

  • преобразует аргумент в число и возвращает , если оно является обычным числом, т.е. не :

Иногда используется для проверки, содержится ли в строке число:

Помните, что пустая строка интерпретируется как во всех числовых функциях, включая.

Сравнение

Существует специальный метод Object.is, который сравнивает значения примерно как , но более надёжен в двух особых ситуациях:

  1. Работает с : , здесь он хорош.
  2. Значения и разные: , это редко используется, но технически эти значения разные.

Во всех других случаях идентичен .

Этот способ сравнения часто используется в спецификации JavaScript. Когда внутреннему алгоритму необходимо сравнить 2 значения на предмет точного совпадения, он использует (Определение ).

generator.throw

Как мы видели в примерах выше, внешний код может вернуть генератору в качестве результата любое значение.

…Но «вернуть» можно не только результат, но и ошибку!

Для того, чтобы передать в ошибку, используется вызов . При этом на строке с возникает исключение.

Например, в коде ниже обращение к внешнему коду завершится с ошибкой:

«Вброшенная» в строке ошибка возникает в строке с . Далее она обрабатывается как обычно. В примере выше она перехватывается и выводится.

Если ошибку не перехватить, то она «выпадет» из генератора. По стеку ближайший вызов, который инициировал выполнение – это строка с . Можно перехватить её там, как и продемонстрировано в примере ниже:

Если же ошибка и там не перехвачена, то дальше – как обычно, либо снаружи, либо она «повалит» скрипт.

Композиция генераторов

Композиция генераторов – это особенная возможность генераторов, которая позволяет прозрачно «встраивать» генераторы друг в друга.

Например, у нас есть функция для генерации последовательности чисел:

Мы хотели бы использовать её при генерации более сложной последовательности:

  • сначала цифры (с кодами символов 48…57)
  • за которыми следуют буквы в верхнем регистре (коды символов 65…90)
  • за которыми следуют буквы алфавита (коды символов 97…122)

Мы можем использовать такую последовательность для генерации паролей, выбирать символы из неё (может быть, ещё добавить символы пунктуации), но сначала её нужно сгенерировать.

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

Для генераторов есть особый синтаксис , который позволяет «вкладывать» генераторы один в другой (осуществлять их композицию).

Вот генератор с композицией:

Директива делегирует выполнение другому генератору. Этот термин означает, что перебирает генератор и прозрачно направляет его вывод наружу. Как если бы значения были сгенерированы внешним генератором.

Результат – такой же, как если бы мы встроили код из вложенных генераторов:

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

Итого

Чтобы писать числа с большим количеством нулей:

  • Используйте краткую форму записи чисел – , с указанным количеством нулей. Например: это с 6-ю нулями .
  • Отрицательное число после приводит к делению числа на 1 с указанным количеством нулей. Например: это ( миллионных).

Для других систем счисления:

  • Можно записывать числа сразу в шестнадцатеричной (), восьмеричной () и бинарной () системах счисления
  • преобразует строку в целое число в соответствии с указанной системой счисления: .
  • представляет число в строковом виде в указанной системе счисления .

Для преобразования значений типа и в число:

Используйте parseInt/parseFloat для «мягкого» преобразования строки в число, данные функции по порядку считывают число из строки до тех пор пока не возникнет ошибка.

Для дробей:

  • Используйте округления , , , или .
  • Помните, что при работе с дробями происходит потеря точности.

Ещё больше математических функций:

Документация по объекту Math

Библиотека маленькая, но содержит всё самое важное

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector