All numbers in JavaScript, both integer and fractional, are of the Number
type and are stored in the 64-bit IEEE-754 format, also known as “double precision”.
Here we look at the various subtleties associated with working with numbers in JavaScript.
Recording methods
In JavaScript, you can write numbers not only in decimal, but also in hexadecimal (starting with 0x
), as well as octal (starting with 0
) number systems:
Also available is an entry in the "scientific format" (they also say "floating-point entry"), which looks like <число>e<кол-во нулей>
.
For example, 1e3
is 1
with 3
zeros, that is, 1000
.
If the number of zeros is negative, then the number is shifted to the right for the decimal point, so that the decimal fraction is obtained:
Division by Zero, Infinity
Imagine that you are going to create a new language ... People will call it "javascript" (or LiveScript ... whatever).
What should happen when trying to divide by zero?
As a rule, an error in the program ... In any case, in most programming languages this is exactly the case.
But the creator of JavaScript decided more “mathematical” way. After all, the smaller the divider, the greater the result. When dividing by a very, very small number should be very large. In mathematical analysis, this is described in terms of limits, but if simplified, then as a result of dividing by 0
we get “infinity”, which is denoted by the symbol ∞
or, in JavaScript: "Infinity"
.
Infinity
is a special numerical value that behaves exactly like mathematical infinity ∞
.
-
Infinity
greater than any number. - Adding to infinity does not change it.
Infinity can also be assigned explicitly: var x = Infinity
.
It happens and minus infinity -Infinity
:
Infinity can also be obtained if you make a very large number, for which the number of digits in the binary representation does not fit in the corresponding part of the standard 64-bit format, for example:
NaN
If the mathematical operation cannot be performed, then the special value NaN
(Not-A-Number) is returned.
For example, the division 0/0
is undefined in the mathematical sense, therefore it returns NaN
:
The value NaN
used to denote a mathematical error and has the following properties:
If the isNaN
argument is not a number, then it is automatically converted to a number.
No mathematical operations in JavaScript can cause an error or crash the program.
In the worst case, the result will be NaN
.
isFinite(n)
So, in JavaScript there are usual numbers and three special numerical values: NaN
, Infinity
and -Infinity
.
The isFinite(n)
function returns true
only when n
is a regular number and not one of these values:
If the isFinite
argument is not a number, then it is automatically converted to a number.
Conversion to number
Strict conversion can be done by unary plus '+'
Strict means that if the string is not exactly a number, the result will be NaN
:
The only exception is whitespace at the beginning and end of the line, which are ignored:
The transformation in other mathematical operators and functions occurs in a similar way:
Importance: 5
tutorial / intro / sum.html
[Open task in new window]
isNaN
- check for numbers for strings
The isNaN
function is mathematical, it converts an argument to a number, and then checks whether NaN
is or not.
Therefore, you can use it to check:
The only subtle point is that the empty string and the string of whitespace characters are converted to 0
:
And, of course, the isNaN
check isNaN
numbers as false, true, null
, since although they are not numbers, they are converted to them:
Soft transform: parseInt
and parseFloat
In the HTML / CSS world, many values are not exactly numbers. For example, CSS metrics: -12px
or -12px
.
The '+'
operator for such values will return NaN
:
For easy reading of such values, there is a parseInt
function:
parseInt
and its analogue parseFloat
transform a string character by symbol as long as possible.
If an error occurs, the number that was received is returned. parseInt
reads an integer from a string, and parseFloat
a fractional.
Of course, there are situations when parseInt/parseFloat
return NaN
. This happens when an error occurs on the first character:
parseInt
(but not parseFloat
) understands the parseFloat
number system:
In the old JavaScript standard, he knew how to understand and octal:
If you want to be sure that the number starting from zero will be interpreted correctly - use the second optional argument parseInt
- the base of the number system:
Check for numbers for all types
If you need a really accurate check for a number that does not count a string from spaces, logical and special values - use the following function isNumeric
:
return !isNaN(parseFloat(n)) && isFinite(n); |
Let's figure out how it works. Let's start on the right.
- The
isFinite(n)
function converts an argument to a number and returns true
if it is not Infinity/-Infinity/NaN
. Thus, the right-hand side will eliminate non-numbers, but leave such values as true/false/null
and the empty string ''
, since they are correctly converted to numbers.
- To check them you need the left side. Calling
parseFloat(true/false/null/'')
returns NaN
for these values. This is how the parseFloat
function parseFloat
: it converts an argument to a string, i.e. true/false/null
becomes "true"/"false"/"null"
, and then reads a number from it, and an empty string gives NaN
.
As a result, everything is eliminated, except for strings-numbers and ordinary numbers.
toString(система счисления)
As shown above, the numbers can be recorded not only in the 10-hour system, but also in the hexadecimal system. But there is the opposite task: to get a hexadecimal representation of a number. To do this, use the toString(основание системы)
method toString(основание системы)
, for example:
The base can be any from 2
to 36
.
Rounding
One of the most frequent operations with numbers is rounding. In JavaScript, there are as many as 3 functions for this.
-
Math.floor
- Round down
-
Math.ceil
- Round up
-
Math.round
- Rounds to the nearest integer.
Bit operators make any number a 32-bit integer, trimming the decimal part.
As a result, a bitwise operation that does not change the number, for example, a double bit NOT does round it:
Any bitwise operation of this kind is suitable, for example, XOR (XOR, "^"
) with a zero:
This is convenient, first of all, because it is easy to read and does not force you to put additional brackets like Math.floor(...)
:
Rounding to a given accuracy
A common trick is to multiply and divide by 10 with the required number of zeros. For example, round 3.456
to the 2nd decimal place:
This way you can round the number up and down.
num.toFixed(precision)
There is a special method num.toFixed(precision)
, which rounds the number num
to precision
and returns the result as a string :
Rounding goes to the nearest value, similar to Math.round
:
The resulting string, if necessary, is padded with zeros to the desired accuracy:
If we need exactly a number, then we can get it by applying a '+'
to the result of n.toFixed(..)
:
For example, let's round up to one decimal place using two methods:
As you can see, the result is different! The rounding option through
Math.round
is more correct, since according to generally accepted rules
5
rounded up. And
toFixed
can round it both up and down. Why? We will find out soon!
Inaccurate calculations
Run this example:
Run it? If not, do it anyway.
Ok, you launched it. The result is somewhat strange, isn't it? Perhaps a bug in the browser? Change the browser, run again.
Well, now we can be sure: 0.1 + 0.2
is not 0.3
. But then what is it?
As you can see, a small computational error has occurred.
The fact is that in the IEEE 754 standard, exactly 8 bytes (= 64 bits) are allocated to the number, no more and no less.
The number 0.1 (=1/10)
short in decimal format, and in binary notation it is an infinite fraction (conversion of the decimal fraction to binary). Also an infinite fraction is 0.2 (=2/10)
.
The binary value of the infinite fractions is stored only up to a certain sign, so inaccuracy occurs. It can even be seen:
When we add 0.1
and 0.2
, then two inaccuracies are added, we get the third.
Of course, this does not mean that exact calculations for such numbers are impossible. They are possible. And even necessary.
For example, there are two ways to add 0.1
and 0.2
:
- Make them whole, fold, and then divide:
It works because the numbers 0.1*10 = 1
and 0.2*10 = 2
can be accurately represented in the binary system.
- Add and then round to a reasonable decimal. Rounding up to the 10th digit is usually enough to cut off the calculation error:
Importance: 4
In internal binary representation, 6.35
is an infinite binary fraction. It is stored with loss of accuracy .. And by the way, let's see for yourself:
The interpreter sees the number as 6.34...
, therefore it rounds down.
[Open task in new window]
Importance: 5
There are two main approaches.
- You can store the prices themselves in "pennies" (cents, etc.). Then they will always be whole and the problem will disappear. But when showing and exchanging data, you will need to take this into account and do not forget to divide by 100.
- During operations, when it is necessary to obtain the final result - round up to the 2nd decimal place. All that is next is a rounding error:
[Open task in new window]
Hello! I am a number growing by itself!
The reason is the same - loss of accuracy.
Of the 64
bits allocated to the number, the digits of the numbers themselves take up to 52
bits, the remaining 11
bits store the position of the decimal point and one bit is the sign. So if 52
bits are not enough for the digits, then the low bits will disappear when recording.
The interpreter will not give an error, but the result will be “not exactly the number”, which we see in the example above. As the saying goes: "as I could, I wrote it down."
For the sake of justice, we note that exactly the same thing happens in any other language where the IEEE 754 format is used, including Java, C, PHP, Ruby, Perl.
Other Mathematical Methods
JavaScript provides basic trigonometric and some other functions for working with numbers.
Trigonometry
Built-in functions for trigonometric calculations:
-
Math.acos(x)
- Returns the arc cosine
x
(in radians) -
Math.asin(x)
- Returns the arcsine
x
(in radians) -
Math.atan
- Returns the arctangent of
x
(in radians) -
Math.atan2(y, x)
- Returns the angle to the point
(y, x)
. Function Description: Atan2. -
Math.sin(x)
- Calculates the sine of
x
(in radians) -
Math.cos(x)
- Calculates the cosine of
x
(in radians) -
Math.tan(x)
- Returns the tangent of
x
(in radians)
General purpose functions
Various useful features:
-
Math.sqrt(x)
- Returns the square root of
x
. -
Math.log(x)
- Returns the natural (base
e
) logarithm of x
. -
Math.pow(x, exp)
- Raises the number to the power, returns
x exp
, for example, Math.pow(2,3) = 8
. It also works with fractional and negative powers, for example: Math.pow(4, -1/2) = 0.5
. -
Math.abs(x)
- Returns the absolute value of a number.
-
Math.exp(x)
- Returns
e x
, where e
is the base of the natural logarithms. -
Math.max(a, b, c...)
- Returns the largest of the list of arguments.
-
Math.min(a, b, c...)
- Returns the smallest of the argument list.
-
Math.random()
- Returns a pseudo-random number in the range [0,1 0,1) - that is, between 0 (inclusive) and 1 (excluding). The random number generator is initialized by the current time.
Total
- Numbers can be written in hexadecimal, octal, as well as "scientific" way.
- In JavaScript, there is a numeric value infinity
Infinity
. - Calculation error gives
NaN
. - Arithmetic and mathematical functions convert a string exactly to a number, ignoring leading and trailing spaces.
- The
parseInt/parseFloat
make numbers from strings that start with a number. - There are four rounding methods:
Math.floor
, Math.round
, Math.ceil
and the bit operator. To round to the desired character, use +n.toFixed(p)
or a trick with multiplication and division by 10 p
. - Fractional numbers give a calculation error. If necessary, it can be cut off by rounding to the desired character.
- Random numbers from
0
to 1
generated using Math.random()
, the rest are converted from them.
There are other math functions. You can find them in the directory in the sections Number and Math.
Importance: 4
Because i
will never be equal to 10
.
Run to see real i
values:
None of them is exactly 10
.
[Open task in new window]
Importance: 3
The function may be:
... Or, much simpler, like this:
function getDecimal(num) { |
Usually, the function does not work correctly due to inaccurate framing algorithms.
For example:
You can add toFixed
rounding to drop extra characters:
[Open task in new window]
Importance: 4
Calculation according to the corollary of Binet’s formula:
Note that the calculation uses the rounding of Math.round
, since you need exactly the nearest integer .
The result of calculating the F 77
wrong!
It differs from that calculated in another way. The reason is in rounding errors, because √5 is an infinite fraction.
Rounding errors in the calculations are multiplied and, as a result, give a discrepancy.
[Open task in new window]
Importance: 2
Generate a value in the range 0..1
and multiply by max
:
[Open task in new window]
Importance: 2
Generate a value from the interval 0..max-min
, and then shift to min
:
[Open task in new window]
Importance: 2
The simplest, but wrong way is to generate a value in the interval min..max
and round it Math.round
, like this:
var rand = min + Math.random()*(max-min) |
It is working. But at the same time the probability of getting the extreme values min
and max
is two times less than any other.
For example, let's find values between 1 and 3 in this way:
var rand = 1 + Math.random()*(3-1) |
The call will Math.round()
round the values as follows:
значения из диапазона 1 ... 1.499+ станут 1 |
значения из диапазона 1.5 ... 2.499+ станут 2 |
значения из диапазона 2.5 ... 2.999+ станут 3 |
From here it is already clear that the range 1
(as well as 3
) falls in two times smaller than that in 2
. So it 1
will be issued twice less than 2
.
The right way: Math.round(случайное от min-0.5 до max+0.5)
In this case, the range will be the same ( max-min+1
), but the rounding mechanics are taken into account round
.
Альтернативный путь - применить округление Math.floor()
к случайному числу от min
до max+1
.
Например, для генерации целого числа от 1
до 3
, создадим вспомогательное случайное значение от 1
до 4
(не включая 4
).
Тогда Math.floor()
округлит их так:
Все диапазоны одинаковы.
Итак, код:
[Open task in new window]
Comments
To leave a comment
Scripting client side JavaScript, jqvery, BackBone
Terms: Scripting client side JavaScript, jqvery, BackBone