translate

This commit is contained in:
Ilya Kantor 2016-03-06 00:59:16 +03:00
parent 811a6c7920
commit 98c987e794
84 changed files with 826 additions and 880 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

View file

@ -23,13 +23,12 @@ Besides regular numbers there are so-called "special numeric values" which also
```js run
alert( 1 / 0 ); // Infinity
alert( -1 / 0 ); // -Infinity
```
Also we can use it directly:
Or just mention it in the code directly:
```js run
alert( Infinity > 123456789 ); // true
alert( Infinity ); // Infinity
```
- `NaN` represents a computational error. It is a result of an incorrect or an undefined mathematical operation, for instance:
@ -37,7 +36,21 @@ Besides regular numbers there are so-called "special numeric values" which also
alert( "not a number" * 2 ); // NaN
```
These values formally belong to the "number" type. Of course they are not numbers in a common sense of this word.
`NaN` is sticky. Any further operation on `NaN` would give `NaN`:
```js run
alert( "not a number" * 2 + 5 - 9 ); // still NaN
```
So, in a long mathematical expression if we have `NaN` in one place, it propagates to the whole result.
```smart header="Maths is safe"
Maths is safe in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc.
The script will never die. At worst we'll get `NaN` as the result.
```
Special numeric values formally belong to the "number" type. Of course they are not numbers in a common sense of this word.
We'll see more into working with numbers in the chapter <info:number>.
@ -57,7 +70,7 @@ In JavaScript, there are 3 types of quotes.
Double and single quotes are essentially the same.
Backtricks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example:
Backticks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example:
```js run
let name = "John";
@ -69,16 +82,16 @@ alert( `Hello, ${name}!` ); // Hello, John!
alert( `the result is ${1 + 2}` ); // the result is 3
```
The expression inside `${…}` is evaluated and the result becomes a part of the string.
The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex.
We'll cover strings more thoroughly in the chapter <info:string>.
```smart header="There is no *character* type."
In some languages, there is a special "character" type for a single character. For example, in the C language it is `char`.
In JavaScript, there is no such type. There's only one type `string` for both a single character and long texts.
In JavaScript, there is no such type. There's only one type: `string`. A string may consist of only one character or many of them.
```
We'll cover strings more thoroughly in the chapter <info:string>.
## A boolean (logical)
The boolean type has only two values: `true` and `false`.
@ -96,7 +109,7 @@ Boolean values also come as the result of comparisons:
```js run
let isGreater = 4 > 1;
alert(isGreater); // true
alert( isGreater ); // true
```
We'll cover booleans more deeply while discussing logical operators.
@ -174,33 +187,72 @@ alert( user.name ); // John
alert( user.age ); // 30
```
Also we can add new information to the user and remove it any time:
Also we can add new information to the user any time later:
```js
user.isAdmin = true;
```
...Or remove it with the help of `delete` operator:
```js
delete user.age;
```
Objects in JavaScript are very powerful. This topic is so huge. We'll be closely working with objects since the chapter <info:object> and continue studying them in following parts of the tutorial.
Any string can be used as a property name. But if it has multiple words, then we should use another kind of notation to access it. Namely, square brackets:
```js
user["likes to swim?"] = true;
```
See, the dot requires the property name to be a valid variable identifier. That is: no spaces and other limitations. Square brackets work with any string.
We can split the code above into two lines by putting the property name into a variable:
```js
let key = "likes to swim?";
user[key] = true; // same as above
```
Objects in JavaScript are very powerful. Here we just started the topic that is really huge. We'll be closely working with objects in the next parts of the tutorial.
## Symbol type
The `symbol` type stands apart from the others. Symbols are rarely used. Probably we won't need them any time soon, but it's the 7th and the last type of the language. So we must mention it for the sake of completeness.
The `symbol` type stands apart from the others. Probably we won't need them any time soon, but it's the 7th and the last type of the language. So we must mention it for the sake of completeness.
Type "symbol" represents an unique identifier.
Type "symbol" represents an unique identifier with a given name.
A value of this type can be created like this:
```js
// id is a symbol with the name "id"
let id = Symbol("id");
```
Symbols are used in advanced operations with objects. As of now, it's enough to understand that JavaScript symbols is a separate primitive type used for identifiers.
Symbols in JavaScript are different from symbols in Ruby language (if you are familiar with it, please don't get trapped by the same word) in that two symbols with the same name are different:
Symbols in JavaScript are different from symbols in Ruby language (if you are familiar with it, please don't get trapped by the same word). We'll get back to them after in-depth study of objects.
```js run
let id1 = Symbol("id");
let id2 = Symbol("id");
alert(id1 == id2); // false
```
Symbols is a separate primitive type used for identifiers, which are guaranteed to be unique.
So if we want to create a "hidden" property in an object, only for us, and ensure that no other part of code can occasionally access it, we can create a symbol for it:
```js run
let user = { name: "John" };
let id = Symbol("id");
user[id] = "Secret ID Value";
alert( user[id] ); // we can access the data
```
Now, if another script wants his own "id" property inside `user`, it can create its own `Symbol("id")`. There will be no conflict, because symbols are always different.
Symbols are widely used by the JavaScript language itself to store "system" properties. We'll find out more details after studying objects.
## The typeof operator [#type-typeof]
@ -245,7 +297,7 @@ Please note the last two lines, because `typeof` behaves specially there.
## Type conversions
A variable in JavaScript can contain any data. The same variable can get a string and, a little bit later, be used to store a number:
A variable in JavaScript can contain any data. A variable can at one moment be a string and later recieve a numeric value:
```js
// no error
@ -253,7 +305,9 @@ let message = "hello";
message = 123456;
```
...But sometimes we need to convert a value from one type to another. That is useful because each type has it's own features. So we are really going to benefit from storing a number as a number, not a string with it.
...But sometimes we need to convert a value from one type to another. For example, `alert` automatically converts any value to a string, to show it. Or, so to say, an `if (value)` converts it's argument into a boolean to see if it's `true` or `false`.
There are also cases when we need to convert between types to ensure that we store the right data the right way, or to use special features of a certain type.
There are many type conversions in JavaScript, fully listed in [the specification](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-type-conversion).
@ -263,6 +317,8 @@ Three conversions that happen most often are:
2. Numeric conversion.
3. Boolean conversion.
Let's see how and when they happen.
### String conversion
The string conversion happens when we need a string form of a value.
@ -358,13 +414,16 @@ alert( Boolean(" ") ); // any non-empty string, even whitespaces are true
## Summary
- There are 7 basic types in JavaScript. Six "primitive" types: `number`, `string`, `boolean`, `null`, `undefined`, `symbol` and an `object` type.
- The `typeof` operator allows to see which type is stored in the variable, but note that it mistakingly returns `"object"` for `null`.
There are 7 basic types in JavaScript.
Type conversions usually happen automatically, but there are also functions for the manual conversion:
- `number` for numbers of any kind, can convert into it using `Number(value)`.
- `string` for strings and characters, can convert into it using `String(value)`.
- `boolean` for `true`/`false`, can convert into it using `Boolean(value)`.
- `null` for unknown values.
- `undefined` for unassigned values.
- `object` for complex data structures.
- `symbol` for unique identifiers.
- String
- Number
- Boolean
The `typeof` operator allows to see which type is stored in the variable, but note that it mistakingly returns `"object"` for `null`.
Now let's study operators and other language constructs that actually form our code.

View file

@ -1,4 +1,4 @@
# Coding style
# TODO: Coding style
Our code must be as clean and easy to read as possible.

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View file

@ -1,4 +1,4 @@
# Как писать неподдерживаемый код?
# TODO: Как писать неподдерживаемый код?
```warn header="Познай свой код"
Эта статья представляет собой мой вольный перевод [How To Write Unmaintainable Code](http://mindprod.com/jgloss/unmain.html) ("как писать неподдерживаемый код") с дополнениями, актуальными для JavaScript.

View file

@ -1,4 +1,4 @@
# Автоматические тесты при помощи chai и mocha
# TODO: Автоматические тесты при помощи chai и mocha
В этой главе мы разберём основы автоматического тестирования. Оно будет применяться далее в задачах, и вообще, входит в "образовательный минимум" программиста.

View file

@ -1,4 +1,4 @@
# Code quality
# TODO: Code quality
In order to keep the code quality, you need at least:
<ol>

View file

@ -0,0 +1,31 @@
Try running it:
```js run
let str = "Hello";
str.test = 5; // (*)
alert(str.test);
```
There may be two kinds of result:
1. `undefined`
2. An error.
Why? Let's replay what's happening at line `(*)`:
1. When a property of `str` is accessed, a "wrapper object" is created.
2. The operation with the property is carried out on it. So, the object gets the `test` property.
3. The operation finishes and the "wrapper object" disappears.
So, on the last line, `str` has no trace of the property. A new wrapper object for every object operation on a string.
Some browsers though may decide to further limit the programmer and disallow to assign properties to primitives at all. That's why in practice we can also see errors at line `(*)`. It's a little bit farther from the specification though.
**This example clearly shows that primitives are not objects.**
They just can not store data.
All property/method operations are performed with the help of temporary objects.

View file

@ -0,0 +1,18 @@
importance: 5
---
# Can I add a string property?
Consider the following code:
```js
let str = "Hello";
str.test = 5;
alert(str.test);
```
How do you think, will it work? What will be shown?

View file

@ -0,0 +1,119 @@
# Types: Primitives as Objects
As we know from the chapter <info:types>, there are 7 data types in JavaScript:
- Six primitive types: `string`, `number`, `boolean`, `symbol`, `null` and `undefined`.
- One `object` type for anything else.
In this section of the tutorial we are going to study them in more detail. But first let's learn more about how primitives and objects are related.
## Primitives as objects
Before this chapter, we discussed primitives and objects as something truly separate. But in some aspects, JavaScript allows to work with primitives as if they were objects. This ability may even lead to opinions like 'everything in JavaScript behaves as an object'. But in fact it's not quite so. And here we plan to put it clear.
Let's formulate the definitive distinction between primitives and objects.
A primitive
: Is a single value. Like a number `123`. Or a string `"Hello"`.
An object
: Is capable of storing multiple values as properties.
An empty object: `{}`. An object with two properties: `{name: "John", age: 30}`.
Objects in JavaScript are not just a "collection of values". One of best things about them is that we can store a function as one of properties:
```js run
let john = { name: "John" };
john.sayHi = function() {
alert("Hi buddy!");
}
john.sayHi(); // (*)
```
Now as we assigned a function to `john.sayHi`, the object can speak!
That is how a so-called "object-oriented code" is written. We make objects which reflect entities of the real world: like a user John, or a document, or a button that is clickable etc.
An object stores its data in regular properties (like `name`, `age` etc) and has functions to express itself. Function properties are usually called *methods*. So, one can say that in the code above "`sayHi` is a method of the object `john`".
```warn header="Brackets are required for the call"
Please note that we do need brackets in line `(*)` after `john.sayHi` if we want to run the method.
Without them, `john.sayHi` only gives us the function, doesn't run it.
```
There are many kinds of objects, including those that work with dates, errors, parts of the webpage etc. They have different properties and methods.
But features come at a price. Objects are "heavier" than primitives. They require additional resources for the machinery. But accessing properties and methods looks good. We can easily create methods of our own.
## Primitive as an object
So here's the paradox faced by the creator of JavaScript:
- Objects are sweet. There are many things one would want to do with a string or a number, could be great to access them as methods.
- Primitives must store a single value, be as fast and lightweight as possible.
The solution looks a little bit awkward, but here it is.
1. Primitives are still primitive. A single value, as discussed.
2. The language allows to access methods and properties of strings, numbers, booleans and symbols.
3. When it happens, a special "object wrapper" is created that provides the functionality and then is destroyed.
The "object wrappers" are different for each primitive type and are named specifically: `String`, `Number`, `Boolean` and `Symbol`. Thus they provide different sets of methods.
For instance, a string has a method [toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) that returns the capitalized string.
Here's how it works:
```js run
let str = "Hello";
alert( str.toUpperCase() ); // HELLO
```
Simple, right? And here's what actually happens in `str.toUpperCase()`:
1. A special object is created which has the string value in it and also provides string methods, like `toUpperCase()`.
2. The method runs and returns a new string (shown up).
3. The special object disappears, leaving the primitive `str` alone.
So, primitives can provide methods, but they still remain lightweight.
Of course, the JavaScript engine highly optimizes that process. Internally it may skip the creation of the extra object at all, so it's not so costly performance-wise.
A number has methods of it's own, for instance, [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) rounds the number to the given precision:
```js run
let n = 1.23456;
alert( n.toFixed(2) ); // 1.23
```
We'll see more into specific methods in next chapters.
Now please ensure that you really grasped that by solving the first task in this chapter (below).
````warn header="null/undefined have no methods"
Special types `null` and `undefined` are exceptions. They have no corresponding "wrapper objects" and provide no methods. In a sense, they are "the most primitive".
An attempt to access a property of such value would give an error:
```js run
alert(null.test); // error
````
## Summary
- Primitives except `null` and `undefined` provide various methods. We plan to study those in the next sections.
- Still, primitives are not objects. Formally, methods work via temporary objects that are created "just for the call". The JavaScript engines are tuned to optimize that internally, so it's not expensive at all.

View file

@ -1,106 +0,0 @@
# Введение в методы и свойства
Все значения в JavaScript, за исключением `null` и `undefined`, содержат набор вспомогательных функций и значений, доступных "через точку".
Такие функции называют "методами", а значения -- "свойствами". Здесь мы рассмотрим основы использования свойств и методов.
[cut]
## Свойство str.length
У строки есть *свойство* `length`, содержащее длину:
```js run
alert( "Привет, мир!".length ); // 12
```
Можно и записать строку в переменную, а потом запросить её свойство:
```js run
var str = "Привет, мир!";
alert( str.length ); // 12
```
## Метод str.toUpperCase()
Также у строк есть *метод* `toUpperCase()`, который возвращает строку в верхнем регистре:
```js run
var hello = "Привет, мир!";
*!*
alert( hello.toUpperCase() ); // "ПРИВЕТ, МИР!"
*/!*
```
````warn header="Вызов метода -- через круглые скобки!"
Обратите внимание, для вызова метода обязательно нужны круглые скобки.
Посмотрите, например, результат обращения к `toUpperCase` без скобок:
```js run
var hello = "Привет";
*!*
alert( hello.toUpperCase ); // function...
*/!*
```
Метод -- это встроенная команда ("функция", мы поговорим о них позже), которую нужно вызвать для получения значения. При обращении без скобок мы получим саму эту функцию. Как правило браузер выведет её как-то так: `"function toUpperCase() { ... }"`.
А чтобы получить результат -- нужно произвести её вызов, добавив скобки:
```js run
var hello = "Привет";
*!*
alert( hello.toUpperCase() ); // ПРИВЕТ
*/!*
```
````
Более подробно с различными свойствами и методами строк мы познакомимся в главе <info:string>.
## Метод num.toFixed(n)
Есть методы и у чисел, например `num.toFixed(n)`. Он округляет число `num` до `n` знаков после запятой, при необходимости добивает нулями до данной длины и возвращает в виде строки (удобно для форматированного вывода):
```js run
var n = 12.345;
alert( n.toFixed(2) ); // "12.35"
alert( n.toFixed(0) ); // "12"
alert( n.toFixed(5) ); // "12.34500"
```
Детали работы `toFixed` разобраны в главе <info:number>.
````warn header="Обращение к методам чисел"
К методу числа можно обратиться и напрямую:
```js run
alert( 12.34.toFixed(1) ); // 12.3
```
...Но если число целое, то будет проблема:
```js run no-beautify
alert(12.toFixed(1)); // ошибка!
```
Ошибка произойдёт потому, что JavaScript ожидает десятичную дробь после точки.
Это -- особенность синтаксиса JavaScript. Вот так -- будет работать:
```js run
alert( 12..toFixed(1) ); // 12.0
```
````
## Итого
В этой главе мы познакомились с методами и свойствами.
Почти все значения в JavaScript, кроме разве что `null` и `undefined` имеют их и предоставляют через них разный функционал.
Далее мы подробно разберём основные свойства и методы структур данных в JavaScript.

View file

@ -1,10 +1,12 @@
```js run demo
var a = +prompt("Введите первое число", "");
var b = +prompt("Введите второе число", "");
let a = +prompt("The first number?", "");
let b = +prompt("The second number?", "");
alert( a + b );
```
Обратите внимание на оператор `+` перед `prompt`, он сразу приводит вводимое значение к числу. Если бы его не было, то `a` и `b` были бы строками и складывались бы как строки, то есть `"1" + "2" = "12"`.
Note the unary plus `+` before `prompt`. It immediately converts the value to a number.
Otherwise, `a` and `b` would be string their sum would be their concatenation, that is: `"1" + "2" = "12"`.

View file

@ -2,10 +2,10 @@ importance: 5
---
# Интерфейс суммы
# Sum numbers from the visitor
Создайте страницу, которая предлагает ввести два числа и выводит их сумму.
Create a script that prompts the visitor to enter two numbers and then shows their sum.
[demo]
P.S. Есть "подводный камень" при работе с типами.
P.S. There is a gotcha with types.

View file

@ -1,7 +1,33 @@
Во внутреннем двоичном представлении `6.35` является бесконечной двоичной дробью. Хранится она с потерей точности.. А впрочем, посмотрим сами:
Internally the decimal fraction `6.35` is an endless binary. As always in such cases, it is stored with a precision loss.
Let's see:
```js run
alert( 6.35.toFixed(20) ); // 6.34999999999999964473
```
Интерпретатор видит число как `6.34...`, поэтому и округляет вниз.
The precision loss can cause both increase and decrease of a number. In this particular case the number becomes a tiny bit less, that's why it rounded down.
And what's for `1.35`?
```js run
alert( 1.35.toFixed(20) ); // 1.35000000000000008882
```
Here the precision loss made the number a little bit greater, so it rounded up.
**How can we fix the problem with `6.35` if we want it to be rounded the right way?**
We should use bring it closer to an integer prior to rounding:
```js run
alert( (6.35 * 10).toFixed(20) ); // 63.50000000000000000000
```
Note that `63.5` has no precision loss at all. That's because the decimal part `0.5` is actually `1/2`. Fractions divided by powers of `2` are exactly represented in the binary system, now we can round it:
```js run
alert( Math.round(6.35 * 10) / 10); // 6.35 -> 63.5 -> 63(rounded) -> 6.3
```

View file

@ -2,18 +2,21 @@ importance: 4
---
# Почему 6.35.toFixed(1) == 6.3?
# Why 6.35.toFixed(1) == 6.3?
В математике принято, что `5` округляется вверх, например:
According to the documentation `Math.round` and `toFixed` both round to the nearest number: `0..4` lead down while `5..9` lead up.
For instance:
```js run
alert( 1.5.toFixed(0) ); // 2
alert( 1.35.toFixed(1) ); // 1.4
```
Но почему в примере ниже `6.35` округляется до `6.3`?
How do you think why in the similar example below `6.35` is rounded to `6.3`, not `6.4`?
```js run
alert( 6.35.toFixed(1) ); // 6.3
```
How to round `6.35` the right way?

View file

@ -0,0 +1,12 @@
function readNumber() {
let num;
do {
num = prompt("Enter a number please?", 0);
} while ( !isFinite(num) );
if (num === null || num === '') return null;
return +num;
}

View file

@ -0,0 +1,38 @@
beforeEach(function() {
sinon.stub(window, "prompt");
});
afterEach(function() {
prompt.restore();
});
describe("readNumber", function() {
it("if a number, returns it", function() {
prompt.returns("123");
assert.strictEqual(readNumber(), 123);
});
it("if 0, returns it", function() {
prompt.returns("0");
assert.strictEqual(readNumber(), 0);
});
it("continues the loop unti meets a number", function() {
prompt.onCall(0).returns("not a number");
prompt.onCall(1).returns("not a number again");
prompt.onCall(2).returns("1");
assert.strictEqual(readNumber(), 1);
});
it("if an empty line, returns null", function() {
prompt.returns("");
assert.isNull(readNumber());
});
it("if cancel, returns null", function() {
prompt.returns(null);
assert.isNull(readNumber());
});
});

View file

@ -0,0 +1,23 @@
```js run demo
function readNumber() {
let num;
do {
num = prompt("Enter a number please?", 0);
} while ( !isFinite(num) );
if (num === null || num === '') return null;
return +num;
}
alert(`Read: ${readNumber()}`);
```
The solution is a little bit more intricate that it could be because we need to handle `null`/empty lines.
So we actually accept the input until it is a "regular number". Both `null` (cancel) and empty line also fit that condition, because in numeric form they are `0`.
After we stopped, we need to treat `null` and empty line specially (return `null`), because converting them to a number would return `0`.

View file

@ -0,0 +1,14 @@
importance: 5
---
# Repeat until the input is a number
Create a function `readNumber` which prompts for a number until the visitor enters a valid numeric value.
The resulting value must be returned as a number.
The visitor can also stop the process by entering an empty line or pressing "CANCEL". In that case, the function should return `null`.
[demo]

View file

@ -1,9 +0,0 @@
Есть два основных подхода.
1. Можно хранить сами цены в "копейках" (центах и т.п.). Тогда они всегда будут целые и проблема исчезнет. Но при показе и при обмене данными нужно будет это учитывать и не забывать делить на 100.
2. При операциях, когда необходимо получить окончательный результат -- округлять до 2го знака после запятой. Все, что дальше -- ошибка округления:
```js run no-beautify
var price1 = 0.1, price2 = 0.2;
alert( +(price1 + price2).toFixed(2) );
```

View file

@ -1,17 +0,0 @@
importance: 5
---
# Сложение цен
Представьте себе электронный магазин. Цены даны с точностью до копейки(цента, евроцента и т.п.).
Вы пишете интерфейс для него. Основная работа происходит на сервере, но и на клиенте все должно быть хорошо. Сложение цен на купленные товары и умножение их на количество является обычной операцией.
Получится глупо, если при заказе двух товаров с ценами `0.10$` и `0.20$` человек получит общую стоимость `0.30000000000000004$`:
```js run
alert( 0.1 + 0.2 + '$' );
```
Что можно сделать, чтобы избежать проблем с ошибками округления?

View file

@ -1,13 +1,17 @@
Потому что `i` никогда не станет равным `10`.
That's because `i` would never equal `10`.
Запустите, чтобы увидеть *реальные* значения `i`:
Run it to see the *real* values of `i`:
```js run
var i = 0;
let i = 0;
while (i < 11) {
i += 0.2;
if (i > 9.8 && i < 10.2) alert( i );
}
```
Ни одно из них в точности не равно `10`.
None of them is exactly `10`.
Such things happen because of the precision losses when adding fractions like `0.2`.
Conclusion: evade equality checks when working with decimal fractions.

View file

@ -2,12 +2,12 @@ importance: 4
---
# Бесконечный цикл по ошибке
# An occasional infinite loop
Этот цикл - бесконечный. Почему?
This loop is infinite. It never ends. Why?
```js
var i = 0;
let i = 0;
while (i != 10) {
i += 0.2;
}

View file

@ -1,7 +0,0 @@
function getDecimal(num) {
var str = "" + num;
var zeroPos = str.indexOf(".");
if (zeroPos == -1) return 0;
str = str.slice(zeroPos);
return +str;
}

View file

@ -1,21 +0,0 @@
describe("getDecimal", function() {
it("возвращает дробную часть 1.2 как 0.2", function() {
assert.equal(getDecimal(1.2), 0.2);
});
it("возвращает дробную часть 1.3 как 0.3", function() {
assert.equal(getDecimal(1.3), 0.3);
});
it("возвращает дробную часть 12.345 как 0.345", function() {
assert.equal(getDecimal(12.345), 0.345);
});
it("возвращает дробную часть -1.2 как 0.2", function() {
assert.equal(getDecimal(-1.2), 0.2);
});
it("возвращает дробную часть 5 как 0", function() {
assert.equal(getDecimal(5), 0);
});
});

View file

@ -1,77 +0,0 @@
# Функция
Первая идея может быть такой:
```js run
function getDecimal(num) {
return num - Math.floor(num);
}
alert( getDecimal(12.5) ); // 0.5
*!*
alert( getDecimal(-1.2) ); // 0.8, неверно!
*/!*
```
Как видно из примера выше, для отрицательных чисел она не работает.
Это потому, что округление `Math.floor` происходит всегда к ближайшему меньшему целому, то есть `Math.floor(-1.2) = -2`, а нам бы хотелось убрать целую часть, т.е. получить `-1`.
Можно попытаться решить проблему так:
```js run
function getDecimal(num) {
return num > 0 ? num - Math.floor(num) : Math.ceil(num) - num;
}
alert( getDecimal(12.5) ); // 0.5
*!*
alert( getDecimal(-1.2) ); // 0.19999999999999996, неверно!
alert( getDecimal(1.2) ); // 0.19999999999999996
*/!*
```
Проблема с отрицательными числами решена, но результат, увы, не совсем тот.
Внутреннее неточное представление чисел приводит к ошибке в вычислениях, которая проявляется при работе и с положительными и с отрицательными числами.
Давайте попробуем ещё вариант -- получим остаток при делении на `1`. При таком делении от любого числа в остатке окажется именно дробная часть:
```js run
function getDecimal(num) {
return num > 0 ? (num % 1) : (-num % 1);
}
alert( getDecimal(12.5) ); // 0.5
*!*
alert( getDecimal(1.2) ); // 0.19999999999999996, неверно!
*/!*
```
В общем-то, работает, функция стала короче, но, увы, ошибка сохранилась.
Что делать?
Увы, операции с десятичными дробями подразумевают некоторую потерю точности.
Зависит от ситуации.
- Если внешний вид числа неважен и ошибка в вычислениях допустима -- она ведь очень мала, то можно оставить как есть.
- Перейти на промежуточные целочисленные вычисления там, где это возможно.
- Если мы знаем, что десятичная часть жёстко ограничена, к примеру, может содержать не более 2 знаков то можно округлить число, то есть вернуть `+num.toFixed(2)`.
Если эти варианты не подходят, то можно работать с числом как со строкой:
```js run
function getDecimal(num) {
var str = "" + num;
var zeroPos = str.indexOf(".");
if (zeroPos == -1) return 0;
str = str.slice(zeroPos);
return +str;
}
alert( getDecimal(12.5) ); // 0.5
alert( getDecimal(1.2) ); // 0.2
```

View file

@ -1,14 +0,0 @@
importance: 4
---
# Как получить дробную часть числа?
Напишите функцию `getDecimal(num)`, которая возвращает десятичную часть числа:
```js
alert( getDecimal(12.345) ); // 0.345
alert( getDecimal(1.2) ); // 0.2
alert( getDecimal(-1.2) ); // 0.2
```

View file

@ -1,34 +0,0 @@
```js run
function fibBinet(n) {
var phi = (1 + Math.sqrt(5)) / 2;
// используем Math.round для округления до ближайшего целого
return Math.round(Math.pow(phi, n) / Math.sqrt(5));
}
function fib(n) {
var a = 1,
b = 0,
x;
for (i = 0; i < n; i++) {
x = a + b;
a = b
b = x;
}
return b;
}
alert( fibBinet(2) ); // 1, равно fib(2)
alert( fibBinet(8) ); // 21, равно fib(8)
*!*
alert( fibBinet(77) ); // 5527939700884755
alert( fib(77) ); // 5527939700884757, не совпадает!
*/!*
```
**Результат вычисления <code>F<sub>77</sub></code> получился неверным!**
Причина -- в ошибках округления, ведь √5 -- бесконечная дробь.
Ошибки округления при вычислениях множатся и, в итоге, дают расхождение.

View file

@ -1,31 +0,0 @@
importance: 4
---
# Формула Бине
Последовательность [чисел Фибоначчи](http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%A4%D0%B8%D0%B1%D0%BE%D0%BD%D0%B0%D1%87%D1%87%D0%B8) имеет формулу <code>F<sub>n</sub> = F<sub>n-1</sub> + F<sub>n-2</sub></code>. То есть, следующее число получается как сумма двух предыдущих.
Первые два числа равны `1`, затем `2(1+1)`, затем `3(1+2)`, `5(2+3)` и так далее: `1, 1, 2, 3, 5, 8, 13, 21...`.
Код для их вычисления (из задачи <info:task/fibonacci-numbers>):
```js
function fib(n) {
var a = 1,
b = 0,
x;
for (i = 0; i < n; i++) {
x = a + b;
a = b
b = x;
}
return b;
}
```
Существует [формула Бине](http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%A4%D0%B8%D0%B1%D0%BE%D0%BD%D0%B0%D1%87%D1%87%D0%B8#.D0.A4.D0.BE.D1.80.D0.BC.D1.83.D0.BB.D0.B0_.D0.91.D0.B8.D0.BD.D0.B5), согласно которой <code>F<sub>n</sub></code> равно ближайшему целому для <code>ϕ<sup>n</sup>/√5</code>, где <code>ϕ=(1+√5)/2</code> -- золотое сечение.
Напишите функцию `fibBinet(n)`, которая будет вычислять <code>F<sub>n</sub></code>, используя эту формулу. Проверьте её для значения <code>F<sub>77</sub></code> (должно получиться `fibBinet(77) = 5527939700884757`).
**Одинаковы ли результаты, полученные при помощи кода `fib(n)` выше и по формуле Бине? Если нет, то почему и какой из них верный?**

View file

@ -1,8 +0,0 @@
Сгенерируем значение в диапазоне `0..1` и умножим на `max`:
```js run
var max = 10;
alert( Math.random() * max );
```

View file

@ -1,7 +0,0 @@
importance: 2
---
# Случайное из интервала (0, max)
Напишите код для генерации случайного значения в диапазоне от `0` до `max`, не включая `max`.

View file

@ -1,9 +1,19 @@
Сгенерируем значение из интервала `0..max-min`, а затем сдвинем на `min`:
We need to "map" all values from the interval 0..1 into values from `min` to `max`.
That can be done in two stages:
1. If we multiply a random number from 0..1 by `max-min`, then it the interval of possible values increases `0..1` to `0..max-min`.
2. Now if we add `min`, the possible interval becomes from `min` to `max`.
The function:
```js run
var min = 5,
max = 10;
function random(min, max) {
return min + Math.random() * (max - min);
}
alert( min + Math.random() * (max - min) );
alert( random(1, 5) );
alert( random(1, 5) );
alert( random(1, 5) );
```

View file

@ -2,6 +2,18 @@ importance: 2
---
# Случайное из интервала (min, max)
# A random number from min to max
Напишите код для генерации случайного числа от `min` до `max`, не включая `max`.
The built-in function `Math.random()` creates a random value from `0` to `1` (not including `1`).
Write the function `random(min, max)` to generate a random floating-point number from `min` to `max` (not including `max`).
Examples of its work:
```js
alert( random(1, 5) ); // 1.2345623452
alert( random(1, 5) ); // 3.7894332423
alert( random(1, 5) ); // 4.3435234525
```
You can use the solution of the [previous task](info:task/random-min-max) as the base.

View file

@ -1,75 +1,66 @@
# Очевидное неверное решение (round)
# The simple but wrong solution
Самый простой, но неверный способ -- это сгенерировать значение в интервале `min..max` и округлить его `Math.round`, вот так:
The simplest, but wrong solution would be to generate a value from `min` to `max` and round it:
```js run
function randomInteger(min, max) {
var rand = min + Math.random() * (max - min)
rand = Math.round(rand);
return rand;
let rnd = min + Math.random() * (max - min);
return Math.round(rnd);
}
alert( randomInteger(1, 3) );
```
Эта функция работает. Но при этом она некорректна: вероятность получить крайние значения `min` и `max` будет в два раза меньше, чем любые другие.
The function works, but it is incorrect. The probability to get edge values `min` and `max` is two times less than any other.
При многократном запуске этого кода вы легко заметите, что `2` выпадает чаще всех.
If you run the example above many times, you would easily see that `2` appears the most often.
Это происходит из-за того, что `Math.round()` получает разнообразные случайные числа из интервала от `1` до `3`, но при округлении до ближайшего целого получится, что:
That happens because `Math.round()` gets random numbers from the interval `1..3` and rounds them as follows:
```js no-beautify
значения из диапазона 1 ... 1.49999.. станут 1
значения из диапазона 1.5 ... 2.49999.. станут 2
значения из диапазона 2.5 ... 2.99999.. станут 3
values from 1 ... to 1.4999999999 become 1
values from 1.5 ... to 2.4999999999 become 2
values from 2.5 ... to 2.9999999999 become 3
```
Отсюда явно видно, что в `1` (как и `3`) попадает диапазон значений в два раза меньший, чем в `2`. Из-за этого такой перекос.
Now we can clearly see that `1` gets twice less values than `2`. And the same with `3`.
# Верное решение с round
# The correct solution
Правильный способ: `Math.round(случайное от min-0.5 до max+0.5)`
There are many correct solutions to the task. One of them is to adjust interval borders. To ensure the same intervals, we can generate values from `0.5 to 2.5`, thus adding the required probabilities to the edges:
```js run
*!*
function randomInteger(min, max) {
var rand = min - 0.5 + Math.random() * (max - min + 1)
rand = Math.round(rand);
return rand;
}
// now rnd is from (min-0.5) to (max+0.5)
let rnd = min - 0.5 + Math.random() * (max - min + 1);
return Math.round(rnd);
}
*/!*
alert( randomInteger(5, 10) );
alert( randomInteger(1, 3) );
```
В этом случае диапазон будет тот же (`max-min+1`), но учтена механика округления `round`.
# Решение с floor
Альтернативный путь - применить округление `Math.floor()` к случайному числу от `min` до `max+1`.
Например, для генерации целого числа от `1` до `3`, создадим вспомогательное случайное значение от `1` до `4` (не включая `4`).
Тогда `Math.floor()` округлит их так:
```js no-beautify
1 ... 1.999+ станет 1
2 ... 2.999+ станет 2
3 ... 3.999+ станет 3
```
Все диапазоны одинаковы.
Итак, код:
An alternative way could be to use `Math.floor` for a random number from `min` to `max+1`:
```js run
*!*
function randomInteger(min, max) {
var rand = min + Math.random() * (max + 1 - min);
rand = Math.floor(rand);
return rand;
}
// here rnd is from min to (max+1)
let rnd = min + Math.random() * (max + 1 - min);
return Math.floor(rand);
}
*/!*
alert( randomInteger(5, 10) );
alert( randomInteger(1, 3) );
```
Now all intervals are mapped this way:
```js no-beautify
values from 1 ... to 1.9999999999 become 1
values from 2 ... to 2.9999999999 become 2
values from 3 ... to 3.9999999999 become 3
```
All intervals have the same length, making the final distribution uniform.

View file

@ -2,8 +2,17 @@ importance: 2
---
# Случайное целое от min до max
# A random integer from min to max
Напишите функцию `randomInteger(min, max)` для генерации случайного **целого** числа между `min` и `max`, включая `min,max` как возможные значения.
Create a function `randomInteger(min, max)` that generates a random *integer* number from `min` to `max` including both `min` and `max` as possible values.
Любое число из интервала `min..max` должно иметь одинаковую вероятность.
Any number from the interval `min..max` must appear with the same probability.
Examples of its work:
```js
alert( random(1, 5) ); // 1
alert( random(1, 5) ); // 3
alert( random(1, 5) ); // 5
```

View file

@ -1,537 +1,443 @@
# Числа
# Numbers
Все числа в JavaScript, как целые так и дробные, имеют тип `Number` и хранятся в 64-битном формате [IEEE-754](http://en.wikipedia.org/wiki/IEEE_754-1985), также известном как "double precision".
All numbers in JavaScript are stored in 64-bit format [IEEE-754](http://en.wikipedia.org/wiki/IEEE_754-1985) also known as "double precision".
Здесь мы рассмотрим различные тонкости, связанные с работой с числами в JavaScript.
Let's recap what we know about them and add a little bit more.
## Способы записи
## Advanced ways to write
В JavaScript можно записывать числа не только в десятичной, но и в шестнадцатеричной (начинается с `0x`), а также восьмеричной (начинается с `0`) системах счисления:
Imagine, we need to write a billion. The obvious way is:
```js run
alert( 0xFF ); // 255 в шестнадцатиричной системе
alert( 010 ); // 8 в восьмеричной системе
```js
let billion = 1000000000;
```
Также доступна запись в *"научном формате"* (ещё говорят "запись с плавающей точкой"), который выглядит как `<число>e<кол-во нулей>`.
But in real life we usually dislike writing many zeroes. It's easy to mistype. Also we are lazy. We we usually write something like `"1bn"` for a billion or `"7.3bn"` for 7 billions 300 millions. The similar is true for other big numbers.
Например, `1e3` -- это `1` с `3` нулями, то есть `1000`.
In JavaScript, we can do almost the same by appending the letter `e` to the number and specifying the zeroes count:
```js run
// еще пример научной формы: 3 с 5 нулями
alert( 3e5 ); // 300000
let billion = 1e9; // 1 billion, literally: 1 and 9 zeroes
alert( 7.3e9 ); // 7.3 billions (7,300,000,000)
```
Если количество нулей отрицательно, то число сдвигается вправо за десятичную точку, так что получается десятичная дробь:
In other words, `e` multiplies the number by `1` with the given zeroes count.
```js
1e3 = 1 * 1000
1.23e6 = 1.23 * 1000000
```
Now let's write something very small. Say, 1 microsecond is one millionth of a second:
```js
let ms = 0.000001;
```
Also the same `e` can help. If we'd like not to write down the zeroes explicitly, the same number is:
```js
let ms = 1e-6; // six zeroes to the left from 1
```
If we count the zeroes in `0.000001`, there are 6 of them. So naturally it's `1e-6`.
In other words, a negative number after `e` means a division by 1 with the given number of zeries:
```js
// -3 divides by 1 with 3 zeroes
1e-3 = 1 / 1000 (=0.001)
// -6 divides by 1 with 6 zeroes
1.23e-6 = 1.23 / 1000000 (=0.00000123)
```
## Hex, binary and octal numbers
Hexadecimal numbers are widely used in JavaScript: to represent colors, encode characters and for many other things. So there exists a short way to write them: `0x` and then the number.
For instance:
```js run
// здесь 3 сдвинуто 5 раз вправо, за десятичную точку.
alert( 3e-5 ); // 0.00003 <-- 5 нулей, включая начальный ноль
alert( 0xff ); // 255
alert( 0xFF ); // the same, letters can be uppercased, doesn't matter
```
## Деление на ноль, Infinity
Представьте, что вы собираетесь создать новый язык... Люди будут называть его "JavaScript" (или LiveScript... неважно).
Что должно происходить при попытке деления на ноль?
Как правило, ошибка в программе... Во всяком случае, в большинстве языков программирования это именно так.
Но создатель JavaScript решил пойти математически правильным путем. Ведь чем меньше делитель, тем больше результат. При делении на очень-очень маленькое число должно получиться очень большое. В математическом анализе это описывается через [пределы](http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%B5%D0%BB_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0&#041;), и если подразумевать предел, то в качестве результата деления на `0` мы получаем "бесконечность", которая обозначается символом `∞` или, в JavaScript: `"Infinity"`.
Binary and octal numeral systems are rarely used, but also possible to write them right way:
```js run
alert( 1 / 0 ); // Infinity
alert( 12345 / 0 ); // Infinity
let a = 0b11111111; // binary form of 255
let b = 0o377; // octal form of 255
alert( a == b ); // true, the same number 255 at both sides
```
**`Infinity` -- особенное численное значение, которое ведет себя в точности как математическая бесконечность `∞`.**
So as you can see, we prepend the number with `0x` for a hex, `0b` for a binary and `0o` for an octal.
- `Infinity` больше любого числа.
- Добавление к бесконечности не меняет её.
## toString(base)
There is also a "reverse" method `num.toString(base)` that returns a string representation of `num` in the given `base`.
For example:
```js run
let num = 255;
alert( num.toString(2) ); // 11111111
alert( num.toString(8) ); // 377
```
The `base` can vary from `2` to `36`.
Most often use cases are:
- **16**, because hexadecimal numeral system is used for colors, character encodings etc, digits can be `0..9` or `A..F`.
- **2** is mostly for debugging bitwise operations, digits can be only `0` or `1`.
- **36** is the maximum, digits can be `0..9` or `A..Z`. The whole latin alphabet is used to represent a number.
A funny, but useful case for `36` is when we need to turn a long numeric identifier into something shorter, for example to make a short url. The base-36 notation is an easy way to go:
```js run
alert( Infinity > 1234567890 ); // true
alert( Infinity + 5 == Infinity ); // true
alert( 123456..toString(36) ); // 2n9c
```
**Бесконечность можно присвоить и в явном виде: `var x = Infinity`.**
```warn header="Two dots to call a method"
If we want to call a method directly on a number, like `toString` in the example above, then we need to place two dots `..` after it.
Бывает и минус бесконечность `-Infinity`:
```js run
alert( -1 / 0 ); // -Infinity
If we place a single dot: `123456.toString(36)`, then there will be an error, because JavaScript awaits the decimal part after the dot. And if we place one more dot, then JavaScript knows that the number has finished and we mean the method.
```
Бесконечность можно получить также, если сделать ну очень большое число, для которого количество разрядов в двоичном представлении не помещается в соответствующую часть стандартного 64-битного формата, например:
## Rounding
One of most often operations with numbers is the rounding.
There are following built-in functions for rounding:
`Math.floor`
: Rounds down: `3.1` becomes `3`, and `-1.1` becomes `-2`.
`Math.ceil`
: Rounds up: `3.1` becomes `4`, and `-1.1` becomes `-1`.
`Math.round`
: Rounds to the nearest integer: `3.1` becomes `3`, `3.6` becomes `4` and `-1.1` becomes `-1`.
`Math.trunc` (not supported by Internet Explorer)
: Removes the decimal part: `3.1` becomes `3`, `-1.1` becomes `-1`.
Looks simple, right? Indeed it is.
Here's the table to make edge cases more obvious:
| | `floor` | `ceil` | `round` | `trunc` |
|---|---------|--------|---------|---------|
|`3.1`| `3` | `4` | `3` | `3` |
|`3.6`| `3` | `4` | `4` | `3` |
|`-1.1`| `-2` | `-1` | `-1` | `-1` |
|`-1.6`| `-2` | `-1` | `-2` | `-1` |
These functions cover all possible ways to deal with the decimal part.
But what if we'd like to round the number to `n-th` digit after the point?
For instance, we have `1.2345` and want to round it to 2 digits, getting only `1.23`.
There are two ways to do so.
1. Multiply-and-divide.
For instance, to round the number to the 2nd digit after the point, we can multiply the number by `100`, call the rounding function and then divide back.
```js run
let num = 1.23456;
alert( Math.floor(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23
```
2. The method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) rounds the number to `n` digits after the point and returns a string representation of the result.
```js run
let num = 12.34;
alert( num.toFixed(1) ); // "12.3"
```
The rounding goes to the nearest value, similar to `Math.round`:
```js run
let num = 12.36;
alert( num.toFixed(1) ); // "12.4"
```
The resulting string is zero-padded to the required precision if needed:
```js run
let num = 12.34;
alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits
```
Let's note once again that the result is a string. We can convert it to a number using the unary plus or a `Number()` call.
## Imprecise calculations
Internally, each number occupies 64 bits, 52 of them are used to store the digits, 11 of them store the location of the point (to allow fractions) and 1 is the sign.
If a number is too big, it would overflow the storage, potentially giving an infinity:
```js run
alert( 1e500 ); // Infinity
```
## NaN
But what happens much more often is the loss of precision.
Если математическая операция не может быть совершена, то возвращается специальное значение `NaN` (Not-A-Number).
Например, деление `0/0` в математическом смысле неопределено, поэтому его результат `NaN`:
Consider this:
```js run
alert( 0 / 0 ); // NaN
alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!*
```
Значение `NaN` используется для обозначения математической ошибки и обладает следующими свойствами:
- Значение `NaN` -- единственное, в своем роде, которое *не равно ничему, включая себя*.
Следующий код ничего не выведет:
```js run
if (NaN == NaN) alert( "==" ); // Ни один вызов
if (NaN === NaN) alert( "===" ); // не сработает
```
- Значение `NaN` можно проверить специальной функцией `isNaN(n)`, которая преобразует аргумент к числу и возвращает `true`, если получилось `NaN`, и `false` -- для любого другого значения.
```js run
var n = 0 / 0;
alert( isNaN(n) ); // true
alert( isNaN("12") ); // false, строка преобразовалась к обычному числу 12
```
````smart header="Забавный способ проверки на `NaN`"
Отсюда вытекает забавный способ проверки значения на `NaN`: можно проверить значение на равенство самому себе, если не равно -- то `NaN`:
```js run
var n = 0 / 0;
if (n !== n) alert( 'n = NaN!' );
```
Это работает, но для наглядности лучше использовать `isNaN(n)`.
````
- Значение `NaN` "прилипчиво". Любая операция с `NaN` возвращает `NaN`.
```js run
alert( NaN + 1 ); // NaN
```
Если аргумент `isNaN` -- не число, то он автоматически преобразуется к числу.
```smart header="Математические операции в JS безопасны"
Никакие математические операции в JavaScript не могут привести к ошибке или "обрушить" программу.
В худшем случае, результат будет `NaN`.
```
## isFinite(n)
Итак, в JavaScript есть обычные числа и три специальных числовых значения: `NaN`, `Infinity` и `-Infinity`.
Тот факт, что они, хоть и особые, но -- числа, демонстрируется работой оператора `+`:
```js run
var value = prompt("Введите Infinity", 'Infinity');
*!*
var number = +value;
*/!*
alert( number ); // Infinity, плюс преобразовал строку "Infinity" к такому "числу"
```
Обычно если мы хотим от посетителя получить число, то `Infinity` или `NaN` нам не подходят. Для того, чтобы отличить "обычные" числа от таких специальных значений, существует функция `isFinite`.
**Функция `isFinite(n)` преобразует аргумент к числу и возвращает `true`, если это не `NaN/Infinity/-Infinity`:**
```js run
alert( isFinite(1) ); // true
alert( isFinite(Infinity) ); // false
alert( isFinite(NaN) ); // false
```
## Преобразование к числу
Большинство арифметических операций и математических функций преобразуют значение в число автоматически.
Для того, чтобы сделать это явно, обычно перед значением ставят унарный плюс `'+'`:
```js run
var s = "12.34";
alert( +s ); // 12.34
```
При этом, если строка не является в точности числом, то результат будет `NaN`:
```js run
alert( +"12test" ); // NaN
```
Единственное исключение -- пробельные символы в начале и в конце строки, которые игнорируются:
```js run
alert( +" -12" ); // -12
alert( +" \n34 \n" ); // 34, перевод строки \n является пробельным символом
alert( +"" ); // 0, пустая строка становится нулем
alert( +"1 2" ); // NaN, пробел посередине числа - ошибка
```
Аналогичным образом происходит преобразование и в других математических операторах и функциях:
```js run
alert( '12.34' / "-2" ); // -6.17
```
## Мягкое преобразование: parseInt и parseFloat
В мире HTML/CSS многие значения не являются в точности числами. Например, метрики CSS: `10pt` или `-12px`.
Оператор `'+'` для таких значений возвратит `NaN`:
```js run
alert(+"12px") // NaN
```
Для удобного чтения таких значений существует функция `parseInt`:
```js run
alert( parseInt('12px') ); // 12
```
**Функция `parseInt` и ее аналог `parseFloat` преобразуют строку символ за символом, пока это возможно.**
При возникновении ошибки возвращается число, которое получилось. Функция `parseInt` читает из строки целое число, а `parseFloat` -- дробное.
```js run
alert(parseInt('12px')) // 12, ошибка на символе 'p'
alert(parseFloat('12.3.4')) // 12.3, ошибка на второй точке
```
Конечно, существуют ситуации, когда `parseInt/parseFloat` возвращают `NaN`. Это происходит при ошибке на первом же символе:
```js run
alert( parseInt('a123') ); // NaN
```
## Проверка на число
Для проверки строки на число можно использовать функцию `isNaN(str)`.
Она преобразует строку в число аналогично `+`, а затем вернёт `true`, если это `NaN`, т.е. если преобразование не удалось:
```js run
var x = prompt("Введите значение", "-11.5");
if (isNaN(x)) {
alert( "Строка преобразовалась в NaN. Не число" );
} else {
alert( "Число" );
}
```
Однако, у такой проверки есть две особенности:
1. Пустая строка и строка из пробельных символов преобразуются к `0`, поэтому считаются числами.
2. Если применить такую проверку не к строке, то могут быть сюрпризы, в частности `isNaN` посчитает числами значения `false, true, null`, так как они хотя и не числа, но преобразуются к ним.
```js run
alert( isNaN(null) ); // false - не NaN, т.е. "число"
alert( isNaN("\n \n") ); // false - не NaN, т.е. "число"
```
Если такое поведение допустимо, то `isNaN` -- приемлемый вариант.
Если же нужна действительно точная проверка на число, которая не считает числом строку из пробелов, логические и специальные значения, а также отсекает `Infinity` -- используйте следующую функцию `isNumeric`:
```js
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
```
Разберёмся, как она работает. Начнём справа.
- Функция `isFinite(n)` преобразует аргумент к числу и возвращает `true`, если это не `Infinity/-Infinity/NaN`.
Таким образом, правая часть отсеет заведомо не-числа, но оставит такие значения как `true/false/null` и пустую строку `''`, т.к. они корректно преобразуются в числа.
- Для их проверки нужна левая часть. Вызов `parseFloat(true/false/null/'')` вернёт `NaN` для этих значений.
Так устроена функция `parseFloat`: она преобразует аргумент к строке, т.е. `true/false/null` становятся `"true"/"false"/"null"`, а затем считывает из неё число, при этом пустая строка даёт `NaN`.
В результате отсеивается всё, кроме строк-чисел и обычных чисел.
## toString(система счисления)
Как показано выше, числа можно записывать не только в 10-чной, но и в 16-ричной системе. Но бывает и противоположная задача: получить 16-ричное представление числа. Для этого используется метод `toString(основание системы)`, например:
```js run
var n = 255;
alert( n.toString(16) ); // ff
```
В частности, это используют для работы с цветовыми значениями в браузере, вида `#AABBCC`.
Основание может быть любым от `2` до `36`.
- Основание `2` бывает полезно для отладки побитовых операций:
```js run
var n = 4;
alert( n.toString(2) ); // 100
```
- Основание `36` (по количеству букв в английском алфавите -- 26, вместе с цифрами, которых 10) используется для того, чтобы "кодировать" число в виде буквенно-цифровой строки. В этой системе счисления сначала используются цифры, а затем буквы от `a` до `z`:
```js run
var n = 1234567890;
alert( n.toString(36) ); // kf12oi
```
При помощи такого кодирования можно "укоротить" длинный цифровой идентификатор, например чтобы выдать его в качестве URL.
## Округление
Одна из самых частых операций с числом -- округление. В JavaScript существуют целых 3 функции для этого.
`Math.floor`
: Округляет вниз
`Math.ceil`
: Округляет вверх
`Math.round`
: Округляет до ближайшего целого
```js run no-beautify
alert( Math.floor(3.1) ); // 3
alert( Math.ceil(3.1) ); // 4
alert( Math.round(3.1) ); // 3
```
````smart header="Округление битовыми операторами"
[Битовые операторы](/bitwise-operators) делают любое число 32-битным целым, обрезая десятичную часть.
В результате побитовая операция, которая не изменяет число, например, двойное битовое НЕ -- округляет его:
```js run
alert( ~~12.3 ); // 12
```
Любая побитовая операция такого рода подойдет, например XOR (исключающее ИЛИ, `"^"`) с нулем:
```js run
alert( 12.3 ^ 0 ); // 12
alert( 1.2 + 1.3 ^ 0 ); // 2, приоритет ^ меньше, чем +
```
Это удобно в первую очередь тем, что легко читается и не заставляет ставить дополнительные скобки как `Math.floor(...)`:
```js
var x = a * b / c ^ 0; // читается как "a * b / c и округлить"
```
````
### Округление до заданной точности
Для округления до нужной цифры после запятой можно умножить и поделить на 10 с нужным количеством нулей. Например, округлим `3.456` до 2го знака после запятой:
```js run
var n = 3.456;
alert( Math.round(n * 100) / 100 ); // 3.456 -> 345.6 -> 346 -> 3.46
```
Таким образом можно округлять число и вверх и вниз.
### num.toFixed(precision)
Существует также специальный метод `num.toFixed(precision)`, который округляет число `num` до точности `precision` и возвращает результат *в виде строки*:
```js run
var n = 12.34;
alert( n.toFixed(1) ); // "12.3"
```
Округление идёт до ближайшего значения, аналогично `Math.round`:
```js run
var n = 12.36;
alert( n.toFixed(1) ); // "12.4"
```
Итоговая строка, при необходимости, дополняется нулями до нужной точности:
```js run
var n = 12.34;
alert( n.toFixed(5) ); // "12.34000", добавлены нули до 5 знаков после запятой
```
Если нам нужно именно число, то мы можем получить его, применив `'+'` к результату `n.toFixed(..)`:
```js run
var n = 12.34;
alert( +n.toFixed(5) ); // 12.34
```
````warn header="Метод `toFixed` не эквивалентен `Math.round`!"
Например, произведём округление до одного знака после запятой с использованием двух способов: `toFixed` и `Math.round` с умножением и делением:
```js run
var price = 6.35;
alert( price.toFixed(1) ); // 6.3
alert( Math.round(price * 10) / 10 ); // 6.4
```
Как видно, результат разный! Вариант округления через `Math.round` получился более корректным, так как по общепринятым правилам `5` округляется вверх. А `toFixed` может округлить его как вверх, так и вниз. Почему? Скоро узнаем!
````
## Неточные вычисления
Запустите этот пример:
```js run
alert( 0.1 + 0.2 == 0.3 );
```
Запустили? Если нет -- все же сделайте это.
Ок, вы запустили его. Он вывел `false`. Результат несколько странный, не так ли? Возможно, ошибка в браузере? Поменяйте браузер, запустите еще раз.
Хорошо, теперь мы можем быть уверены: `0.1 + 0.2` это не `0.3`. Но тогда что же это?
Yes, you got that right, the sum of `0.1` and `0.2` is not `0.3`. What is it then?
```js run
alert( 0.1 + 0.2 ); // 0.30000000000000004
```
Как видите, произошла небольшая вычислительная ошибка, результат сложения `0.1 + 0.2` немного больше, чем `0.3`.
Imagine you're making an e-shopping site and the visitor puts `$0.10` and `$0.20` goods into his chart. The order total will be `$0.30000000000000004`. That would surprise anyone.
```js run
alert( 0.1 + 0.2 > 0.3 ); // true
Why does it work like that?
A number is stored in memory in it's binary form, as a sequence of ones and zeroes. But decimal fractions like `0.1`, `0.2` are actually unending fractions in their binary form.
In other words, what is `0.1`? It is one divided by ten.
But in the binary numeral system, we can only get "clean" division by the powers of two:
```js
// binary numbers
10 = 1 * 2
100 = 1 * 4
1000 = 1 * 8
...
// now the reverse
0.1 = 1 / 2
0.01 = 1 / 4
0.001 = 1 / 8
...
```
Всё дело в том, что в стандарте IEEE 754 на число выделяется ровно 8 байт(=64 бита), не больше и не меньше.
So, there's just no way to store *exactly 0.1* or *exactly 0.2* as a binary fraction. Just like there is no way to store one-third as a decimal fraction.
Число `0.1 (одна десятая)` записывается просто в десятичном формате, а в двоичной системе счисления это бесконечная дробь ([перевод десятичной дроби в двоичную систему](http://www.klgtu.ru/students/literature/inf_asu/1760.html)). Также бесконечной дробью является `0.2 (=2/10)`.
Двоичное значение бесконечных дробей хранится только до определенного знака, поэтому возникает неточность. Её даже можно увидеть:
The numeric format "fixes" that by storing the nearest possible number. There are rounding rules that normally don't allow us to see that "tiny precision loss", but it still exists.
We can see it like this:
```js run
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
```
Когда мы складываем `0.1` и `0.2`, то две неточности складываются, получаем незначительную, но всё же ошибку в вычислениях.
And when we sum two numbers, then their "precision losses" sum up too.
Конечно, это не означает, что точные вычисления для таких чисел невозможны. Они возможны. И даже необходимы.
That's why `0.1 + 0.2` is not exactly `0.3`.
Например, есть два способа сложить `0.1` и `0.2`:
```smart header="Not only JavaScript"
The same problem exists in many other programming languages.
1. Сделать их целыми, сложить, а потом поделить:
```js run
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
```
Это работает, т.к. числа `0.1*10 = 1` и `0.2*10 = 2` могут быть точно представлены в двоичной системе.
2. Сложить, а затем округлить до разумного знака после запятой. Округления до 10-го знака обычно бывает достаточно, чтобы отсечь ошибку вычислений:
```js run
var result = 0.1 + 0.2;
alert( +result.toFixed(10) ); // 0.3
```
````smart header="Забавный пример"
Привет! Я -- число, растущее само по себе!
```js run
alert( 9999999999999999 ); // выведет 10000000000000000
PHP, Java, C, Perl, Ruby give exactly the same result, because they are based on the same numeric format.
```
Причина та же -- потеря точности.
Can we work around the problem? Sure, there's a number of ways:
Из `64` бит, отведённых на число, сами цифры числа занимают до `52` бит, остальные `11` бит хранят позицию десятичной точки и один бит -- знак. Так что если `52` бит не хватает на цифры, то при записи пропадут младшие разряды.
1. We can round the result with the help of a method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed):
Интерпретатор не выдаст ошибку, но в результате получится "не совсем то число", что мы и видим в примере выше. Как говорится: "как смог, так записал".
```js run
let sum = 0.1 + 0.2;
alert( sum.toFixed(2) ); // 0.30
```
Please note that `toFixed` always returns a string. It ensures that it has 2 digits after the decimal point. That's actually convenient if we have an e-shopping and need to show `$0.30`. For other cases we can use the unary plus to coerce it into a number:
```js run
let sum = 0.1 + 0.2;
alert( +sum.toFixed(2) ); // 0.3
```
2. We can temporarily turn numbers into integers for the maths and then go back. That would looks like this:
```js run
alert( (0.1*10 + 0.2*10) / 10 ); // 0.3
```
It works, because `0.1*10 = 1` and `0.2 * 10 = 2` are integers. The rounding rules of the format fix the precision loss in the process of multiplication. Now the resulting integer numbers can now be exactly represented in the binary format.
3. If it's a shop, then the most radical solution would be to store all prices in cents. No fractions at all. But what if we apply a discount of 30%? In practice, totally evading fractions is rarely feasible, so the solutions listed above are here to help.
````smart header="The funny thing"
Hello! I'm a self-increasing number!
```js run
alert( 9999999999999999 ); // shows 10000000000000000
```
The reason is the same: loss of precision. There are 64 bits for the number, 52 of them can be used to store digits, and that's not enough. So the least significant digits disappear.
JavaScript doesn't trigger an error in such case. It does the best to fit the number into the format. Unfortunately, the format is not big enough.
````
Ради справедливости заметим, что в точности то же самое происходит в любом другом языке, где используется формат IEEE 754, включая Java, C, PHP, Ruby, Perl.
## parseInt and parseFloat
## Другие математические методы
We already know the easiest way to convert a value into a number. It's the unary plus!
JavaScript предоставляет базовые тригонометрические и некоторые другие функции для работы с числами.
But in web-programming we sometimes meet values that
### Тригонометрия
Встроенные функции для тригонометрических вычислений:
## Tests: isFinite and isNaN
`Math.acos(x)`
: Возвращает арккосинус `x` (в радианах)
Remember those two special numeric values?
`Math.asin(x)`
: Возвращает арксинус `x` (в радианах)
- `Infinite` (and `-Infinite`) is a special numeric value that is greater (less) than anything.
- `NaN` represends an error.
`Math.atan(x)`
: Возвращает арктангенс `x` (в радианах)
There are special functions to check for them:
`Math.atan2(y, x)`
: Возвращает угол до точки `(y, x)`. Описание функции: [Atan2](http://en.wikipedia.org/wiki/Atan2).
`Math.sin(x)`
: Вычисляет синус `x` (в радианах)
- `isNaN(value)` converts its argument to a number and then tests if for being `NaN:
`Math.cos(x)`
: Вычисляет косинус `x` (в радианах)
```js run
alert( isNaN(NaN) ); // true
alert( isNaN("str") ); // true
```
`Math.tan(x)`
: Возвращает тангенс `x` (в радианах)
But can't we just use `===` here? Funny, but no. The value `NaN` is unique. It does not equal anything including itself:
### Функции общего назначения
```js run
alert( NaN === NaN ); // false
```
Разные полезные функции:
- `isFinite(value)` converts its argument to a number and returns `true` if it's a regular number, not `NaN/Infinity/-Infinity`:
`Math.sqrt(x)`
: Возвращает квадратный корень из `x`.
```js run
alert( isFinite("15") ); // true
alert( isFinite("str") ); // false, because a special value: NaN
alert( isFinite(Infinity) ); // false, because a special value: Infinity
```
`Math.log(x)`
: Возвращает натуральный (по основанию <code>e</code>) логарифм `x`.
Sometimes `isFinite` is used to validate the string value for being a regular number:
`Math.pow(x, exp)`
: Возводит число в степень, возвращает <code>x<sup>exp</sup></code>, например `Math.pow(2,3) = 8`. Работает в том числе с дробными и отрицательными степенями, например: `Math.pow(4, -1/2) = 0.5`.
`Math.abs(x)`
: Возвращает абсолютное значение числа
`Math.exp(x)`
: Возвращает <code>e<sup>x</sup></code>, где <code>e</code> -- основание натуральных логарифмов.
`Math.max(a, b, c...)`
: Возвращает наибольший из списка аргументов
`Math.min(a, b, c...)`
: Возвращает наименьший из списка аргументов
`Math.random()`
: Возвращает псевдо-случайное число в интервале [0,1) - то есть между 0(включительно) и 1(не включая). Генератор случайных чисел инициализуется текущим временем.
### Форматирование
Для красивого вывода чисел в стандарте [ECMA 402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf) есть метод `toLocaleString()`:
```js run
var number = 123456789;
let num = +prompt("Enter a number", '');
alert( number.toLocaleString() ); // 123 456 789
alert(`num:${num}, isFinite:${isFinite(num)}`);
```
Его поддерживают все современные браузеры, кроме IE10- (для которых нужно подключить библиотеку [Intl.JS](https://github.com/andyearnshaw/Intl.js/)). Он также умеет форматировать валюту и проценты. Более подробно про устройство этого метода можно будет узнать в статье <info:intl>, когда это вам понадобится.
Here `num` is always of a number type, because of the unary plus `+`, but...
## Итого
- It may be `NaN` if the string is non-numeric.
- It may be `Infinity` if the user typed in `"Infinity"`.
- Числа могут быть записаны в шестнадцатиричной, восьмеричной системе, а также "научным" способом.
- В JavaScript существует числовое значение бесконечность `Infinity`.
- Ошибка вычислений дает `NaN`.
- Арифметические и математические функции преобразуют строку в точности в число, игнорируя начальные и конечные пробелы.
- Функции `parseInt/parseFloat` делают числа из строк, которые начинаются с числа.
- Есть четыре способа округления: `Math.floor`, `Math.round`, `Math.ceil` и битовый оператор. Для округления до нужного знака используйте `+n.toFixed(p)` или трюк с умножением и делением на <code>10<sup>p</sup></code>.
- Дробные числа дают ошибку вычислений. При необходимости ее можно отсечь округлением до нужного знака.
- Случайные числа от `0` до `1` генерируются с помощью `Math.random()`, остальные -- преобразованием из них.
The `isFinite` test checks that and returns `true` only if it's a regular number. That's just what we usually need.
Please note that an empty or a space-only string would give `num=0` in the described case.
## parseInt and parseFloat
Regular numeric conversion is harsh. If a value is not exactly a number, it fails:
```js run
alert( +"100px" ); // NaN
```
The sole exception is spaces before and after the line, they are ignored.
But in real life we often have values in units, like `"100px"` or `"12pt"` in CSS. Also in many countries the currency symbol goes after the amount, so we have `"19€"` and would like to extract a numeric value out of that.
That's what `parseInt` and `parseFloat` are for.
They "read" a number from a string until they can. In case of an error, the gathered number is returned. Function `parseInt` reads an integer number, `parseFloat` reads any number:
```js run
alert( parseInt('100px') ); // 100
alert( parseFloat('12.5em') ); // 12.5
alert( parseInt('12.3') ); // 12, only integer part
alert( parseFloat('12.3.4') ); // 12.3, the second point stops the reading
```
Of course, there are situations when `parseInt/parseFloat` return `NaN`. It happens when no digits could be read:
```js run
alert( parseInt('a123') ); // NaN, the first symbol stops he process
```
````smart header="The second argument of `parseInt(str, radix)`"
The `parseInt()` function has an optional second parameter. It specifies the base of the numeral system, so `parseInt` can also parse strings of hex numbers, binary numbers and so on:
```js run
alert( parseInt('0xff', 16) ); // 255
alert( parseInt('ff', 16) ); // 255, without 0x also works
alert( parseInt('2n9c', 36) ); // 123456
```
````
## Other math functions
JavaScript has a built-in [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object which contains a small library of mathematical functions and constants.
A few examples:
`Math.random()`
: Returns a random number from 0 to 1 (not including 1)
```js run
alert( Math.random() ); // 0.1234567894322
alert( Math.random() ); // 0.5435252343232
alert( Math.random() ); // ... (any random numbers)
```
`Math.max(a, b, c...)` / `Math.min(a, b, c...)`
: Return the greatest/smallest from the arbitrary number of arguments.
```js run
alert( Math.max(3, 5, -10, 0, 1) ); // 5
alert( Math.min(1, 2 ); // 1
```
`Math.pow(n, power)`
: Returns `n` raised the given power
```js run
alert( Math.pow(2, 10) ); // 2 in power 10 = 1024
```
You can find the full list of functions in the docs for the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object.
## Summary
To write big numbers:
- Append `e` with the zeroes count to the number. Like: `123e6` is `123` with 6 zeroes.
- A negative number after `e` causes the number to be divided by 1 with given zeroes. That's for one-millionth or such.
For different numeral systems:
- Can write numbers directly in hex (`0x`), octal (`0o`) and binary (`0b`) systems
- `parseInt(str, base)` parses an integer from any numeral system with base: `2 ≤ base ≤ 36`.
- `num.toString(base)` converts a number to a string in the numeral system with the given `base`.
For converting values like `12pt` and `100px` to a number:
- Use `parseInt/parseFloat` for the "soft" conversion, which reads a number from a string until it can.
For fractions:
- Round using `Math.floor`, `Math.ceil`, `Math.trunc`, `Math.round` or `num.toFixed(precision)`.
- Remember about the loss of precision when comparing or doing maths.
Mathematical functions:
- See the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) manual when you need them. The library is very small, but can cover basic needs.
Существуют и другие математические функции. Вы можете ознакомиться с ними в справочнике в разделах <a href="http://javascript.ru/Number">Number</a> и <a href="http://javascript.ru/Math">Math</a>.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After