Как сравнить только дробные части чисел js
Перейти к содержимому

Как сравнить только дробные части чисел js

  • автор:

lua, js — сравнение целых чисел учитывая что они хранятся как double

Известно, что как lua (по умолчанию) так и javascript хранят все числа как IEEE double. Известно также что результаты вычислений во floating point нельзя проверять на совпадаение, т.к. 0.1 + 0.2 != 0.3.

Вопрос — а как в этих языках реализуется целочисленная арифметика? Какие есть гарантии по поводу неё? Тест на js показывает, что (0.7 + 1.9 == 2.6) === false, но (7 + 19 == 26) === true, и даже (7.0 + 19.0 == 26.0), хотя 7 ровно также непредставимо в качестве конечной двоичной дроби как и 0.7. Ясно что оно не сравнивает числа с epsilon допуском, иначе в первом случае было бы true, значит или там хранится флаг целого числа (причём 7.0 тоже считается целым), или результат, достаточно близкий к целому (с достаточным числом нулей после запятой) считается целым. Где про это почитать чтобы не влететь в неожиданности с целыми числами вообще, а в особенности с большими целыми числами, где начнёт сказываться ограничение точности double?

slovazap ★★★★★
04.03.13 23:22:24 MSK

емнип если число целиком влезает в мантиссу то все ок, это какраз в стандарте есть, потому шо 7.0 шо 7 это у тебя не дробь а целое число, а 0.7 дробь

Deleted
( 04.03.13 23:36:17 MSK )
Ответ на: комментарий от Deleted 04.03.13 23:36:17 MSK

for(var i=Math.pow(2,53)+10;i>Math.pow(2,53);--i)

Deleted
( 04.03.13 23:43:05 MSK )

number in Lua is similar to Neko float. Both are by default double-precision IEEE floating point values. And both are customizable to use single precision or even fixed point arithmetics.

это может считаться ответом?

rikardoac ★
( 04.03.13 23:49:21 MSK )
Ответ на: комментарий от Deleted 04.03.13 23:36:17 MSK

О, спасибо. Я почему-то думал что в IEEE мантисса представляет дробную часть из диапазона [0, 1), а оказывается она вполне себе обычное целое число. Получается что от -2^52+1 до 2^52-1 double можно свободно складывать, вычитать и умножать как целые числа?

slovazap ★★★★★
( 05.03.13 00:28:35 MSK ) автор топика
Ответ на: комментарий от slovazap 05.03.13 00:28:35 MSK

IEEE мантисса представляет дробную часть из диапазона

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

Очевидно что если в js у нас «целые» числа станут «дробными» то множество веб-программистов хватит удар, потому видимо решено было до 2^52 их не шокировать

Deleted
( 05.03.13 01:22:41 MSK )
Ответ на: комментарий от slovazap 05.03.13 00:28:35 MSK

бгг http://www.yur.ru/science/computer/IEEE754.htm я пока не прочитал целиком но заголовок доставляет

Deleted
( 05.03.13 01:27:08 MSK )
Ответ на: комментарий от Deleted 05.03.13 01:22:41 MSK

я идиот

все верно, число то представляет дрбную часть, но двоичной дроби, т.е.

Deleted
( 05.03.13 01:37:53 MSK )
anonymous
( 06.03.13 11:08:40 MSK )

Вопрос — а как в этих языках реализуется целочисленная арифметика?

Ну а дробные (2.6 это неправильная дробь, и в двоичном виде бесконечная) — как карта ляжет.

Где про это почитать чтобы не влететь в неожиданности с целыми числами вообще, а в особенности с большими целыми числами, где начнёт сказываться ограничение точности double?

drBatty ★★
( 06.03.13 11:15:10 MSK )
Ответ на: я идиот от Deleted 05.03.13 01:37:53 MSK

угу. Причём первая ВСЕГДА 1, и её потому НЕ хранят.

(кроме нуля). Получается 011001100110011001100110011001100…

drBatty ★★
( 06.03.13 11:19:13 MSK )
Ответ на: комментарий от drBatty 06.03.13 11:15:10 MSK

IEEE-754 гарантирует, что если число представимо как m*2^e (где m и e целые и заранее ограничены в количестве бит), то оно должно быть представлено именно так. Если нет — то заранее оговоренное округление до представимого вида. Про колоду и положения карт там вроде не упоминается.

anonymous
( 06.03.13 11:23:23 MSK )
Ответ на: комментарий от anonymous 06.03.13 11:23:23 MSK

Про колоду и положения карт там вроде не упоминается.

конечно, не упоминается. Сам говоришь — округляется, но не говоришь — ЧТО будет округляться? А от этого ЧТО, зависит — СКОЛЬКО получится. 1.2+3.8 Вполне может получится и 4.(9), что очевидно НЕ равно 5. Сторона, куда округляется число зависит от первого отброшенного бита, а этот бит зависит разве что от погоды на Марсе. Но что самое обидное, 1.2 ты в нормальном виде НЕ представишь, ибо это 6/5. (1.0011001100110011001100110011001100), вероятность того, что отброшенный бит равен 1 равна ровно ½, 4.(9) получается тоже с вероятностью ½. Хоть ты 52й бит отбрасывай, хоть 5552й. Не важно.

drBatty ★★
( 06.03.13 11:54:32 MSK )
Ответ на: комментарий от drBatty 06.03.13 11:54:32 MSK

1. Давай сейчас запусти в большом цикле скрипт/программу/whatever, который складывает double 1.2 и 3.8 и посмотри к чему там сходятся вероятности получить 4.(9) и 5, ок?

2. IEEE-754 одинаково ведет себя на разных платформах, и не зависит от погоды на марсе. То, что у тебя в руках не 1.2, а лишь его неточное представление, не значит, что возникают какие-то вероятности и неопределенности.

anonymous
( 06.03.13 12:05:22 MSK )
Ответ на: комментарий от drBatty 06.03.13 11:54:32 MSK

Образованному человеку, разбирающемуся в теме понятно, что ты хочешь сказать, можешь не разжевывать. Но в качестве обучающего материала на форуме шаманские объяснения использовать не нужно.

anonymous
( 06.03.13 12:08:44 MSK )
Ответ на: комментарий от anonymous 06.03.13 12:05:22 MSK

1. Давай сейчас запусти в большом цикле скрипт/программу/whatever, который складывает double 1.2 и 3.8 и посмотри к чему там сходятся вероятности получить 4.(9) и 5, ок?

не ОК. Голову включи — результат зависит от того, КАКОЙ бит ты отбрасываешь: 45456й или 45457й? Если всегда будешь один и тот же бит отбрасывать — результат будет одинаковый.

Ну и к тому же, разумный компилятор считает 1.2+3.8 константой 5. Целой, ЧСХ. Потому в коде вообще никаких вычислений не будет.

2. IEEE-754 одинаково ведет себя на разных платформах, и не зависит от погоды на марсе. То, что у тебя в руках не 1.2, а лишь его неточное представление, не значит, что возникают какие-то вероятности и неопределенности.

стандарт ничего не говорит о том, ЧЕМУ равно 1.2, и даже как раз наоборот — говорит о том, что ему(стандарту) это неведомо, ибо 1.2 это нецелое число, и в конечную дробь его преобразовать можно только с потерей точности. Также в стандарте не написано, КАКАЯ КОНКРЕТНО будет потеря, даже не написано того, будет-ли 1.2 больше или меньше того, что получится.

IRL это значит только то, что если на i5 получилось 4.(9), то на i7 _может_ получится 5.0. Мало того, результат также зависит от опций компилятора, ибо считать дробные числа можно по разному. В 32х битной версии компилятор любит FPU, а в 64х битной — SSE2. В стандарте не сказано, чем они должны отличаться, и должны-ли. Максимальная погрешность указана, а вот абсолютное значение — увы. Даже знак ошибки неизвестен.

drBatty ★★
( 06.03.13 12:21:17 MSK )
Ответ на: комментарий от anonymous 06.03.13 12:08:44 MSK

Но в качестве обучающего материала на форуме шаманские объяснения использовать не нужно.

Почему же? И кстати, IRL это очень похоже на магию с приворотами и Папюсом — если писать так программу, то она действительно работает в соответствии с тем, в каком доме Меркурий.

вот например здесь: lua, js — сравнение целых чисел учитывая что они хранятся как double (комментарий) другой(я надеюсь) ананимус советует воспользоваться методом тыка в качестве пруфа, а я ему объясняю, что если реципиент умирает в корчах, то это вовсе не обязательно из-за шаманских ритуалов.

drBatty ★★
( 06.03.13 12:27:06 MSK )
Ответ на: комментарий от drBatty 06.03.13 12:21:17 MSK

Вполне ок, как по мне. Цель — проверить детерминизм при равных условиях. Лень или страшно?

стандарт ничего не говорит о том, ЧЕМУ равно 1.2, и даже как раз наоборот — говорит о том, что ему(стандарту) это неведомо, ибо 1.2 это нецелое число, и в конечную дробь его преобразовать можно только с потерей точности. Также в стандарте не написано, КАКАЯ КОНКРЕТНО будет потеря, даже не написано того, будет-ли 1.2 больше или меньше того, что получится.

Действительно, он описывает представимость чисел в ограниченной форме. Соответственно, твой компилятор прекрасно знает, какие байты положить в память, чтобы (пусть и неточно) представить ~1.2. Это касательно конверсии char * -> double. Касательно вычислений — для каждой операции и ее операндов определен результат и погрешность. Берешь 6 и 5, делишь их друг на друга в 80-битном IEEE-754 FPU (как у интела например), и получаешь предсказуемый результат. «(Операция, операнды, флаги поведения) -> (результат, погрешность)».

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

anonymous
( 06.03.13 12:49:48 MSK )
Ответ на: комментарий от anonymous 06.03.13 12:49:48 MSK

Вполне ок, как по мне. Цель — проверить детерминизм при равных условиях. Лень или страшно?

я просто ЗНАЮ, что получится. Получится одно и то же, при всех равных. Это быдлокод называется — код, который работает только на компьютере автора-быдлокодера.

получаешь предсказуемый результат. «(Операция, операнды, флаги поведения) -> (результат, погрешность)«.

да. результат предсказуемый. 5±2¯⁵⁰. Ошибка очень малая, и нам это точно известно. Но НЕИЗВЕСТНО КАКАЯ ИМЕННО.

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

нет. Для целочисленной арифметики нет округления. Округление == потеря информации. Это сложно понять? Когда ты информацию теряешь, получаешь в результате НЁХ. Это как деление на ноль — при умножении на ноль ты теряешь число, а деление — восстановление информации после умножения. Деление на ноль — попытка восстановить безвозвратно потерянное.

drBatty ★★
( 06.03.13 13:58:56 MSK )
Ответ на: комментарий от drBatty 06.03.13 13:58:56 MSK

КОМУ КОНКРЕТНО НЕИЗВЕСТНО?

Для целочисленной арифметики нет округления

Отжег. Спишу на стремительность суждений. Вот пример: 10/3*3/2 == 4 vs 10*3/3/2 == 5. Округление ли это, и влияет ли на него порядок операций — этот вопрос я оставляю на рассмотрение пытливому читателю. Для более продвинутых можно предложить примеры на границе INT_MAX.

Округление == потеря информации. Это сложно понять?

Нет, думаю не сложно. Ты разве это доказывал?

Хватит это делать

anonymous
( 06.03.13 15:01:24 MSK )
Ответ на: комментарий от anonymous 06.03.13 15:01:24 MSK

очевидно — программисту/быдлокодеру неизвестно. Тебя ещё кто-то волнует?

ОК. До какого бита округляет мой процессор? А твой? Чему равен этот бит в числе value? 0 или 1? А после округления?

Вот пример: 10/3*3/2 == 4 vs 10*3/3/2 == 5. Округление ли это

нет. Это деление с остатком. Только остаток ты отбросил, потому и результат разный. Но никто и не обещал тебе, что порядок операций не должен ни на что влиять. Должен, и влияет. И что? Всё равно, 10/3 == 3 в целых числах на ЛЮБОМ железе. Потому-что ЦЕЛЫЕ — ВЕЗДЕ ОДИНАКОВЫЕ, а вот FP — разные. И они НЕ обязаны быть одинаковыми, даже с одной точностью. Это не я такой странный, это мир вокруг нас такой.

drBatty ★★
( 06.03.13 15:18:44 MSK )
Ответ на: комментарий от Deleted 05.03.13 01:27:08 MSK

Так и знал, что они кодировку не осилят.

border-radius ★
( 06.03.13 15:30:23 MSK )
Ответ на: комментарий от drBatty 06.03.13 15:18:44 MSK

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

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

Только остаток ты отбросил, потому и результат разный.

Если бы я не «отбросил остаток» (интересно, как бы это выглядело в коде), я бы получил одинаковый результат в целочисленной арифметике? Давай попробуем:

10/3 -> (3,1) (3,1)*3 -> (9,?) // wtf? (9,?)/2 -> ((4,1),?) // wtwtf? 

Я в замешательстве. Ваши мнения, Господа!

Но никто и не обещал тебе, что порядок операций не должен ни на что влиять.

Я разве говорил что мне кто-то это обещал, но оказалось не так?

Да ничего особенного. Так же как и в плавающей точке. Все операции определены и работают как им полагается.

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

anonymous
( 06.03.13 15:42:01 MSK )
Ответ на: комментарий от anonymous 06.03.13 15:42:01 MSK

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

Вот, пилять, что получается, когда «кодерам» не дают схемотехнику, структуру процессора и ассемблер 🙁

yyk ★★★★★
( 06.03.13 16:23:13 MSK )
Ответ на: комментарий от anonymous 06.03.13 15:42:01 MSK

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

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

С целым числом такого не бывает — оно всегда с одной точностью. ВСЕГДА.

Знаешь чем отличается умножение/деление целых чисел и чисел, построенных на мантиссе-экспоненте? В целых числах, когда разрядность результата больше, чем положено, то отбрасываются старшие биты. Это называется переполнение.

и это нештатная ситуация. Проще говоря — авария.

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

а это уже нормальная штатная работа. С FP всегда так, и это никого не удивляет.

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

тут ты не совсем верно понимаешь: для того, что-бы ошибка была симметричной, считают на 1 бит(как минимум) больше. А затем ОКРУГЛЯЮТ(не путай с усечением). Если лишний бит 1, то к числу прибавляется 1, иначе не прибавляется. Если-бы этого не было, то при _каждой_ операции процессор немного минусовал (в среднем ½ младшего бита), и ошибка накапливалась. Но из-за округления, ошибка всегда составляет ±½ младшего бита, или в среднем равна нулю. Потому ошибки не накапливаются. С умножением схема сложнее, но суть та же.

Если бы я не «отбросил остаток» (интересно, как бы это выглядело в коде), я бы получил одинаковый результат в целочисленной арифметике?

Остаток надо сохранить, и добавлять ПОСЛЕ умножения. Ты что, в школе не учился?

10/3 → (3,1) 3*3+1 -> 10

остаток — это та часть, которую мы НЕ СМОГЛИ поделить. Если мы хотим получить то, что было, надо помножить, и потом добавить остаток. Смотри: поделим 10 яблок между 3я детьми. Для этого СНАЧАЛА надо спрятать одно яблоко, а ПОТОМ поделить 9. Если это сделать иначе — дети будут драться и плакать.

В коде остаток в x86 получается в edx, а в C записывается так:

int r = 10 % 3;// остаток равен 1

напомню, что истинный остаток всегда положительный.

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

просто не нужно выходить за рамки INT_MAX. Это несложно. Если тебе в коде это сложно — используй другой int, побольше. Или тебе 2⁶⁴-1 мало? Проблема FP в том, что у тебя такого выбора нет, даже безобидное 1.2 это бесконечная дробь. Т.е. у тебя ВСЕ числа неточные.

Приближение к INT_MAX испортит твою стройную картину на разных архитектурах.

IRL оно достаточно далеко. У меня сейчас комп 64х битный, т.ч. ты меня не испугал.

Числа

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

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

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

let billion = 1000000000;

Мы также можем использовать символ нижнего подчёркивания _ в качестве разделителя:

let billion = 1_000_000_000

Символ нижнего подчёркивания _ – это «синтаксический сахар», он делает число более читабельным. Движок JavaScript попросту игнорирует _ между цифрами, поэтому в примере выше получается точно такой же миллиард, как и в первом случае.

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

В JavaScript, чтобы укоротить запись числа, мы можем добавить к нему букву «e» и указать необходимое количество нулей:

let billion = 1e9; // 1 миллиард, буквально: 1 и 9 нулей alert( 7.3e9 ); // 7.3 миллиарда (7,300,000,000)

Другими словами, «e» умножает число на 1 с указанным количеством нулей.

1e3 === 1 * 1000 // e3 означает *1000 1.23e6 === 1.23 * 1000000 // e6 означает *1000000

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

let mcs = 0.000001;

В этом случае нам также поможет «e» . Если мы хотим избежать записи длинной последовательности из нулей, мы можем сделать так:

let ms = 1e-6; // шесть нулей слева от 1

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

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

// 1 делится на 1 с 3 нулями 1e-3 === 1 / 1000 (=0.001) // 1.23 делится на 1 с 6 нулями 1.23e-6 === 1.23 / 1000000 (=0.00000123)

Шестнадцатеричные, двоичные и восьмеричные числа

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

alert( 0xff ); // 255 alert( 0xFF ); // 255 (то же самое, регистр не имеет значения)

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

let a = 0b11111111; // двоичная (бинарная) форма записи числа 255 let b = 0o377; // восьмеричная форма записи числа 255 alert( a == b ); // true, с двух сторон число 255

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

toString(base)

Метод num.toString(base) возвращает строковое представление числа num в системе счисления base .

let num = 255; alert( num.toString(16) ); // ff alert( num.toString(2) ); // 11111111

base может варьироваться от 2 до 36 (по умолчанию 10 ).

  • base=16 — для шестнадцатеричного представления цвета, кодировки символов и т.д., цифры могут быть 0..9 или A..F .
  • base=2 — обычно используется для отладки побитовых операций, цифры 0 или 1 .
  • base=36 — максимальное основание, цифры могут быть 0..9 или A..Z . То есть, используется весь латинский алфавит для представления числа. Забавно, но можно использовать 36 -разрядную систему счисления для получения короткого представления большого числового идентификатора. К примеру, для создания короткой ссылки. Для этого просто преобразуем его в 36 -разрядную систему счисления:

alert( 123456..toString(36) ); // 2n9c

Две точки для вызова метода

Внимание! Две точки в 123456..toString(36) это не опечатка. Если нам надо вызвать метод непосредственно на числе, как toString в примере выше, то нам надо поставить две точки .. после числа.

Если мы поставим одну точку: 123456.toString(36) , тогда это будет ошибкой, поскольку синтаксис JavaScript предполагает, что после первой точки начинается десятичная часть. А если поставить две точки, то JavaScript понимает, что десятичная часть отсутствует, и начинается метод.

Также можно записать как (123456).toString(36) .

Округление

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

В JavaScript есть несколько встроенных функций для работы с округлением:

Math.floor Округление в меньшую сторону: 3.1 становится 3 , а -1.1 — -2 . Math.ceil Округление в большую сторону: 3.1 становится 4 , а -1.1 — -1 . Math.round Округление до ближайшего целого: 3.1 становится 3 , 3.6 — 4 , а -1.1 — -1 . Math.trunc (не поддерживается в Internet Explorer) Производит удаление дробной части без округления: 3.1 становится 3 , а -1.1 — -1 .

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

Math.floor Math.ceil Math.round Math.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

Эти функции охватывают все возможные способы обработки десятичной части. Что если нам надо округлить число до n-ого количества цифр в дробной части?

Например, у нас есть 1.2345 и мы хотим округлить число до 2-х знаков после запятой, оставить только 1.23 .

Есть два пути решения:

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

let num = 1.23456; alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23
let num = 12.34; alert( num.toFixed(1) ); // "12.3"

Округляет значение до ближайшего числа, как в большую, так и в меньшую сторону, аналогично методу Math.round :

let num = 12.36; alert( num.toFixed(1) ); // "12.4"

Обратите внимание, что результатом toFixed является строка. Если десятичная часть короче, чем необходима, будут добавлены нули в конец строки:

let num = 12.34; alert( num.toFixed(5) ); // "12.34000", добавлены нули, чтобы получить 5 знаков после запятой

Неточные вычисления

Внутри JavaScript число представлено в виде 64-битного формата IEEE-754. Для хранения числа используется 64 бита: 52 из них используется для хранения цифр, 11 для хранения положения десятичной точки и один бит отведён на хранение знака.

Если число слишком большое, оно переполнит 64-битное хранилище, JavaScript вернёт бесконечность:

alert( 1e500 ); // Infinity

Наиболее часто встречающаяся ошибка при работе с числами в JavaScript – это потеря точности.

Посмотрите на это (неверное!) сравнение:

alert( 0.1 + 0.2 == 0.3 ); // false

Да-да, сумма 0.1 и 0.2 не равна 0.3 .

Странно! Что тогда, если не 0.3 ?

alert( 0.1 + 0.2 ); // 0.30000000000000004

Ой! Здесь гораздо больше последствий, чем просто некорректное сравнение. Представьте, вы делаете интернет-магазин и посетители формируют заказ из 2-х позиций за $0.10 и $0.20 . Итоговый заказ будет $0.30000000000000004 . Это будет сюрпризом для всех.

Но почему это происходит?

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

Другими словами, что такое 0.1 ? Это единица делённая на десять — 1/10 , одна десятая. В десятичной системе счисления такие числа легко представимы, по сравнению с одной третьей: 1/3 , которая становится бесконечной дробью 0.33333(3) .

Деление на 10 гарантированно хорошо работает в десятичной системе, но деление на 3 – нет. По той же причине и в двоичной системе счисления, деление на 2 обязательно сработает, а 1/10 становится бесконечной дробью.

В JavaScript нет возможности для хранения точных значений 0.1 или 0.2, используя двоичную систему, точно также, как нет возможности хранить одну третью в десятичной системе счисления.

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

alert( 0.1.toFixed(20) ); // 0.10000000000000000555

Как у дробного числа откинуть целю часть и округлить до n чисел?

Проверка результата Для проверки подставляйте разные значения переменных a, b и n и проверяйте получившийся результат. Сравнения должны давать соответствующий результат true или false в зависимости от получившихся дробных частей. Примеры для проверки:

Для a = 13.123456789, b = 2.123, n = 5 дробные части: 12345, 12300. Для a = 13.890123, b = 2.891564, n = 2 дробные части: 89, 89. Для a = 13.890123, b = 2.891564, n = 3 дробные части: 890, 891. 

Критерии оценки Для любых значений a, b и n корректно вычисляются дробные части и выводятся результаты сравнения.

Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 21 авг 2020 в 9:45
Andrew Wander Andrew Wander
51 2 2 серебряных знака 8 8 бронзовых знаков
похоже на задачу с codewars
21 авг 2020 в 11:34

5 ответов 5

Сортировка: Сброс на вариант по умолчанию

сам решил таким способом

 function getInteger(a,n)

Отслеживать
4,379 4 4 золотых знака 17 17 серебряных знаков 29 29 бронзовых знаков
ответ дан 21 авг 2020 в 10:16
Andrew Wander Andrew Wander
51 2 2 серебряных знака 8 8 бронзовых знаков
a — Math.floor(a) — бррррррр
21 авг 2020 в 13:45

это плохо? как по мне это самое правильное решение получилось. просто отнимаю дробное число от целого и затем умножаю на 10 в степени n. Тем самым перевел дробное число в целое. Ну а дальше уже сравнение и т.д.

21 авг 2020 в 19:17

Оно заменяется более красивым a % 1 . В целом решение вроде хорошее, но я не уверен, не может ли умножение на степень 10 внести дополнительную погрешность, поэтому в своём ответе использовал другой вариант.

22 авг 2020 в 10:58
как обходите getInteger(5.1, 1) = 0 ?
23 авг 2020 в 21:13

function fr(x, n) < var s = x.toFixed(100) return s.substr(s.indexOf(".") + 1, n).padEnd(n, 0) >for (var n = 1; n for (var n = 98; n
.as-console-wrapper.as-console-wrapper < max-height: 100vh >.as-console-row-code

А вообще, дробная часть числа получается так:

var x = 12.3456789012345 console.log(x % 1)

Отслеживать
ответ дан 21 авг 2020 в 13:44
122k 24 24 золотых знака 124 124 серебряных знака 297 297 бронзовых знаков
1.4%1 = 0.3999999999999999
21 авг 2020 в 13:49
@br3t, и что? Так и должно быть. i.stack.imgur.com/JJoYN.png
21 авг 2020 в 13:51
да, потому, наверное, лучше всего работать с этим как со строками
21 авг 2020 в 13:52

@br3t, но по условию в вопросе уже даны числа, а не строки. Если есть строка, то из моего решения достаточно выкинуть var s = x.toFixed(100)

21 авг 2020 в 13:59

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

21 авг 2020 в 14:05

Получить дробную часть числа можно так:

let number = 5.234 console.log(number.toString().split('.')[1]) 

Отслеживать
ответ дан 21 авг 2020 в 9:56
2,018 8 8 серебряных знаков 28 28 бронзовых знаков
А если number = 0.0000001 ?
21 авг 2020 в 12:03

@Yaant всё равно будет работать, у этого числа дробная часть 0000001 или ты хочешь сказать, что у чисел 0.1 и 0.0001 одинаковая дробная часть? =)

21 авг 2020 в 12:53
(0.0000001).toString() = «1e-7» со всеми вытекающими
21 авг 2020 в 14:08
@br3t не знал об этой особенности js, сегодня попробую =)
23 авг 2020 в 8:38

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

var number = 123.456789; // наше исходное число var fractionalPart = number - Math.floor(number); // его дробная часть fractionalPart -= 0.0005; fractionalPart -= 5 * Math.pow(10, -4); // 4 - число на единицу больше количества знаков, которые нужно оставить после запятой. var result = fractionalPart.toFixed(3); // дробная часть, округлённая до 3 знаков после запятой console.log(result); // 0.456

Отслеживать
ответ дан 21 авг 2020 в 13:31
2,204 1 1 золотой знак 8 8 серебряных знаков 20 20 бронзовых знаков
number — Math.floor(number) — бррррр
21 авг 2020 в 13:45
Кстати, округлять не просили, а в примерах явно видно truncate: 13.123456789 => 12345
21 авг 2020 в 14:43

Это не я округлил, а метод toFixed() 🙂 Сам я против. Но если отрезультата отнять 5 единиц самого младшего разряда, то получится без округления.

21 авг 2020 в 14:52

вот из-за этого toFixed я и решился задать тут вопрос этот) он явно не поможет в этой задаче из-за своей любви к округлению дробной части)

21 авг 2020 в 19:46
Поможет! (но не явно) 🙂 Я переделал ответ.
21 авг 2020 в 21:27

Сделал с помощью объектов Math.

let a = 13.123456789; let b = 2.123; let n = 5; /* let a = 13.890123; let b = 2.891564; let n = 2; let a = 13.890123; let b = 2.891564; let n = 3; */ // целая часть let aFloor = Math.floor(a); let bFloor = Math.floor(b); //дробная часть let aFract = (a % 1); let bFract = (b % 1); let aFractNormalized = Math.round( aFract * Math.pow(10, n) ); let bFractNormalized = Math.round( bFract * Math.pow(10, n) ); console.log('Для a = ', a); console.log('Для b = ', b); console.log('Целая часть a: ', aFloor); console.log('Целая часть b: ', bFloor); console.log('Дробная часть a: ', aFract); console.log('Дробная часть b: ', bFract); console.log('Нормализованная дробная часть a:', aFractNormalized); console.log('Нормализованная дробная часть b:', bFractNormalized); //результаты сравнения >, b', aFractNormalized > bFractNormalized); console.log('a < b', aFractNormalized < bFractNormalized); console.log('a >= b', aFractNormalized >= bFractNormalized); console.log('a  

Работа с числами в JavaScript

В JavaScript в отличие от некоторых других языков программирования имеется только один числовой тип Number . В качестве него используется формат чисел с плавающей точкой двойной точности по стандарту IEEE-754.

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

Пример записи чисел:

let a = 50; // целое число let b = 4.7; // число с дробной частью let c = 2e3; // в экспоненциальной форме 2*10^3 (2000) let d = 5.8e-2; // в экспоненциальной форме 5.8*10^-2 (0,058) let e = 010; // в восьмеричной системы счисления let f = 0xFF; // в шестнадцатеричной системе счисления 

Как показано в примере, в JavaScript числа можно записывать в экспоненциальной форме, а также задавать в других системах счисления: в восьмеричной (впереди 0 ) и шестнадцатеричной (впереди 0x ).

Узнать какой тип данных содержит переменная можно с помощью typeof :

let a = 7.29; console.log(typeof(a)); // number 

Кроме чисел, формат Number также содержит специальные числовые значения:

  • Infinity - положительная бесконечность;
  • -Infinity - отрицательная бесконечность;
  • NaN - не число.

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

console.log(5 / 0); // Infinity console.log(-7 / 0); // -Infinity console.log(3 - '1rem'); // NaN

В JavaScript не возникают ошибки при выполнении математических операций. Если в результате вычисления получается очень большое или маленькое число, выходящее за допустимые границы, то интерпретатор соответственно вернёт Infinity или -Infinity .

Значение NaN возвращается, когда интерпретатор JavaScript не может вычислить математическую операцию . Например, если попытаемся вычесть от числа 3 строку '1rem' .

Числовой тип number является примитивным типом. Но при этом к числам можно применять методы как к объектам. Это осуществляется посредством обёртки Number . Она содержит дополнительные значения и методы для работы с числами:

let num = 10; let str = num.toString(); // "10"

В этом примере мы применили к примитивному типу данных метод toString() как к объекту. При вызове метода числа автоматически оборачиваются в обёртку Number() , а у обёртки имеется метод toString() . Этот метода преобразует число в строку. Этот пример показывает, что числа ведут себя как объекты, хотя на самом деле ими не являются.

При этом использовать обёртку Number напрямую для создания чисел крайне не рекомендуется:

// так создавать числа не нужно let num1 = new Number(10); // всегда создавать числа нужно так let num2 = 10; console.log(typeof num1); // object console.log(typeof num2); // number

В этом примере num1 и num2 имеют разные типы.

Если необходимо использовать методы на числе, то его нужно обернуть в круглые скобки или поставить точку дважды:

console.log((5).toFixed(2)); // 5.00 console.log(5..toFixed(2)); // 5.00 

Кстати, на самом деле в JavaScript 2 числовых типа данных. Второй тип был добавлен в спецификацию ECMAScript 2020 (11 редакция). Называется он bigint . Этот тип предназначен для представления очень больших целых чисел и на практике используется только для чисел, которые слишком велики для представления с помощью number .

Ограничения по максимальному размеру и точность чисел

В JavaScript при сложении чисел с дробной частью можно получить не то число, которое ожидали.

const num = 0.2 + 0.4; // 0.6000000000000001 console.log(num === 0.6); // false

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

Например, число 0.2510 в двоичную систему преобразуется точно:

0.125 x 2 = 0.25 | 0 0.25 x 2 = 0.5 | 0 0.5 x 2 = 1 | 1 0.12510 = 0.0012

Например, число 0.210 можно преобразовать в двоичную систему только с определённой точностью:

0.2 x 2 = 0.4 | 0 0.4 x 2 = 0.8 | 0 0.8 x 2 = 1.6 | 1 0.6 x 2 = 1.2 | 1 0.2 x 2 = 0.4 | 0 0.4 x 2 = 0.8 | 0 0.8 x 2 = 1.6 | 1 0.6 x 2 = 1.2 | 1 0.2 x 2 = 0.4 | 0 0.4 x 2 = 0.8 | 0 0.8 x 2 = 1.6 | 1 0.6 x 2 = 1.2 | 1 . 0.210 = 0.001100110011. 2

В результате эти погрешности скажутся при вычислении выражений и это нужно учитывать при написании кода в JavaScript.

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

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

const num = parseFloat((0.2 + 0.4).toFixed(2), 10); // 0.6 console.log(num === 0.6); // true

В этом примере, мы сначала с использованием метода toFixed(2) получили строковое представление числа, которое является результатом сложения чисел 0.2 и 0.4 , округленных до 2 знаков после точки. После этого с помощью метода parseFloat преобразовали текст в число и полученное значение присвоили переменной num .

Потеря точности может быть связана также с целыми числами, которые выходят за пределы безопасного диапазона:

const num = 9999999999999999; console.log(num); // 10000000000000000

Получить минимальное и максимальное безопасное целое число можно с помощью констант:

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991

Теперь, если проверим число, приведённое выше, то увидим что оно больше безопасного:

const num = 9999999999999999; console.log(num > Number.MAX_SAFE_INTEGER); // true

Кроме этого, проверить находится ли целое число в пределах безопасного диапазона можно посредством метода isSafeInteger :

const num = 9999999999999999; console.log(Number.isSafeInteger(num)); // false

Основные арифметические операторы

В JavaScript имеются следующие математические операторы:

  • сложение: + ;
  • вычитание: - ;
  • умножение: * ;
  • деление: / ;
  • остаток от деления: % ;
  • возведение в степень: ** ;
  • увеличение значения переменной на 1: ++ ;
  • уменьшение значения переменной на 1: -- .
let num; num = 6 + 3; // 9 num = num - 5; // 4 num = 4 * 7; // 28 num = 12 / 2; // 6 num = 11 % 3; // 2 – остаток от деления

Операторы ++ и -- можно располагать как перед переменной, так и после неё:

let num = 3; console.log(num++); // 3 console.log(++num); // 5

Когда мы располагаем оператор ++ после переменной num , то сначала возвращается значение переменной, и только потом увеличивается её значение на 1 .

В другом случае, когда оператор ++ идёт до переменной num, то сначала увеличивается значение этой переменной на 1 , и только потом возвращается её значение.

Оператор -- действует аналогично:

let num = 3; console.log(num--); // 3 console.log(--num); // 1

Кроме этого имеются комбинированные операторы: += , -= , *= , /= , %= и **= :

let num1 = 3; let num2 += 6; // 9

Для сравнения чисел в JavaScript используются следующие операторы :

  • равенство с учетом типа: === , с попыткой преобразования: == ;
  • не равенство с учетом типа: !== , с попыткой преобразования: != ;
  • больше: > , больше или равно: >= ;
  • меньше: < , меньше или равно:
console.log(2 > 3); // false console.log(5 >= 3); // true 

При сравнении чисел необходимо учитывать точность:

console.log((0.2 + 0.4) === 0.6)); // false

Способ сравнить число до двух знаков после плавающей точки:

console.log((0.2 + 0.4).toFixed(2) === (0.6).toFixed(2)); // true

Преобразование строки в число и наоборот

1. Преобразование строки в число

Явно привести строку в число можно разными способами:

1.1. Использовать унарный оператор + , который необходимо расположить перед значением.

console.log(+'7.35'); // 7.35 console.log(+'строка'); // NaN 

Этот способ пренебрегает пробелами в начале и конце строки, а также (переводом строки).

console.log(+' 7.35 '); // 7.35 console.log(+'7.35 '); // 7.35

При использовании оператора + обратите внимание, что '' , ' ' и ' ' преобразуется в число 0 . Значение null и логические значения приводятся к следующим числам:

console.log(+null); // 0 console.log(+true); // 1 console.log(+false); // 0 console.log(+' '); // 0

1.2. С помощью глобальной функции parseInt() или метода Number.parseInt() . Они предназначены для преобразования значения, переданного им на вход, в целое число . В отличие от использования унарного оператора + , эти методы позволяют преобразовать строку в число, в которой не все символы являются цифровыми . Эти методы преобразовывают строку, начиная с первого символа. И как только встречают символ, не являющийся цифровым, они останавливают дальнейший разбор строки и возвращают полученное число:

console.log(parseInt('18px')); // 18 console.log(Number.parseInt('18px')); // 18 console.log(parseInt('33.3%')); // 33 console.log(Number.parseInt('33.3%')); // 33

Эти функции могут работать с разными системами счисления (двоичной, восьмеричной, десятичной, шестнадцатеричной). Основание системы счисления передаётся в вызов parseInt() или Number.parseInt() в качестве второго аргумента.

console.log(parseInt('18px', 10)); // 18 console.log(parseInt('33.3%', 10)); // 33 console.log(parseInt('101', 2)); // 5 console.log(parseInt('B5', 16)); // 181

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

1.3. Для преобразования строки в число с плавающей точкой в JavaScript имеются методы parseFloat() и Number.parseFloat() . Друг от друга они ничем не отличаются, просто последний был добавлен в язык немного позднее:

let num = parseFloat('33.3%'); // 33.3 num = Number.parseFloat('33.3%'); // 33.3 num = parseFloat('3.14'); // 3.14 num = parseFloat('314e-2'); // 3.14 num = parseFloat('0.0314E+2'); // 3.14

Метод parseFloat в отличие от parseInt всегда рассматривает строку как число в десятичной системе счисления. Указать ему другую систему счисления нельзя.

2. Преобразование числа в строку.

Превратить число в строку можно с помощью метода toString() .

let str = (12.8).toString(); // '12.8'

Дополнительно можно передать систему счисления с учётом которой необходимо явно привести число к строке:

const num = 255; const str = num.toString(16); // 'ff'

Проверки: isFinite, isNaN, isInteger

Этот метод позволяет проверить, является ли значение конечным числом. В качестве результата isFinite возвращает true , если значение является конечным числом. В противном случае false :

console.log(Number.isFinite(73)); // true console.log(Number.isFinite(-1 / 0)); // false console.log(Number.isFinite(Infinity)); // false console.log(Number.isFinite(NaN)); // false console.log(Number.isFinite('20')); // false

Кроме Number.isFinite в JavaScript имеется также глобальная функция isFinite . Она в отличие от Number.isFinite выполняет проверку с учетом принудительное приведение переданного ей аргумента к числу:

console.log(Number.isFinite('20')); // false console.log(isFinite('20')); // true

Этот метод объекта Number предназначена для определения того, является ли значение NaN . Если это так, то isNaN возвращает true . В противном случае – false :

console.log(Number.isNaN(NaN)); // true console.log(Number.isNaN(28)); // false console.log(Number.isNaN('')); // false

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

console.log(isNaN(NaN)); // true console.log(isNaN('25px')); // true console.log(isNaN(25.5)); // false console.log(isNaN('25.5')); // false console.log(isNaN('')); // false, т.к. один или несколько пробелов преобразуется к 0 console.log(isNaN(null)); // false console.log(isNaN(true)); // false, т.к. значение true преобразуется к 1

3. Как проверить, является ли значение числом?

В JavaScript имеется метод, который позволяет определить, является ли значение целым числом. Называется он isInteger :

Number.isInteger('20'); // false Number.isInteger(20); // true

В этом примере для '20' мы получили false , т.к. данное значение является строкой.

Если вам нужно проверить является ли значение числом, при это не важно целям или с плавающей точкой, то можно написать, например, вот такую функцию:

// isNumeric const isNumeric = (value) => { return typeof === 'number' && isFinite(value) && !isNaN(value); }

Эта функция в зависимости от результата возвращает true или false .

После этого её можно использовать для проверки следующим образом:

const num1 = '12px'; const num2 = 23; console.log(isNumeric(num1)); // false console.log(isNumeric(num2)); // true

Если нужно проверить строковое значение, то его предварительно нужно преобразовать в строку, например, с помощью метода parseFloat :

const str1 = ''; const str2 = '20px'; console.log(isNumeric(parseFloat(str1))); // false console.log(isNumeric(parseFloat(str2))); // true

При проверке строки '20px' мы получили true , потому что метод parseFloat('20px') возвращает нам число 20 .

Округление

Округление чисел в JavaScript можно выполнить разными способами.

1. С помощью специальных, предназначенных для этой задачи, методов:

  • Math.floor – до ближайшего целого в меньшую сторону;
  • Math.ceil – до ближайшего целого в большую сторону;
  • Math.round – в большую сторону, если дробная часть >= 0.5; иначе в меньшую сторону;
  • Math.trunc – путём отбрасывания дробной части;
let num = Math.floor(7.8); // 7 num = Math.ceil(7.2); // 8 num = Math.round(7.5); // 8 num = Math.trunc(7.9); // 7

2. Посредством toFixed() .

Этот метод округляет дробную часть числа до заданной точности, но результат возвращает в виде строки:

console.log((7.987).toFixed(2)); // "7.99" console.log((7.987).toFixed(5)); // "7.98700" // для дополнительного преобразования в число можно использовать метод parseFloat console.log(parseFloat((7.987).toFixed(2))); // 7.99 console.log(parseFloat((7.987).toFixed(5))); // 7.987 

3. Через toPrecision() .

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

let value = (1001).toPrecision(2); // "1.0e+3" value = (1001).toPrecision(5); // "1001.0" value = (12.4).toPrecision(1); // "1e+1" value = (12.4).toPrecision(2); // "12" value = (12.4).toPrecision(3); // "12.4" value = (12.4).toPrecision(5); // "12.400"

4. С использованием логического оператора ~ или ^ :

// посредством двойного логического НЕ console.log(~~7.9); // 7 // посредством использования логического ИЛИ console.log(7.9 ^ 0); // 7

Форматирование чисел

В JavaScript вывести число в соответствии с региональными стандартами (языковыми настройками операционной системы) позволяет метод toLocaleString() .

В соответствии с настройками установленными в системе:

const num = 345.46; const value = num.toLocaleString(); // "345,46" 

Явно указав регион:

const value = (108.1).toLocaleString('ru-RU'); // "108,1"

Для отображения денежных величин:

let value = (2540.125).toLocaleString('ru-RU', { style: 'currency', currency: 'RUB' }); // "2 540,13 ₽" value = (89.3).toLocaleString('ru-RU', { style: 'currency', currency: 'USD' }); // "89,30 $" value = (2301.99).toLocaleString('ru-RU', { style: 'currency', currency: 'EUR' }); //"2 301,99 €"

В процентном формате:

const value = (0.45).toLocaleString('ru-RU', { style: 'percent' }); // "45 %"

С разделением групп разрядов (свойство useGrouping ):

const value = (125452.32).toLocaleString('ru-RU', { useGrouping: true }); // "125 452,32"

С указанием числа десятичных знаков:

const value = (1240.4564).toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); //"1 240,46"

Примеры

1. Пример, в котором напишем две функции для проверки числа соответственно на четность и не четность . А затем используем их в коде:

// функция для проверки числа на чётность const isEven = (value) => { return value % 2 === 0; } // функция для проверки числа на нечётность const isOdd = (value) => { return Math.abs(value % 2) === 1; } const value = 20; if (Number.isInteger(value) && isEven(value)) { console.log(`Число ${value} чётное!`); } else if (Number.isInteger(value) && isOdd(value)) { console.log(`Число ${value} не чётное!`); } else { console.log(`Значение ${value} не является целым числом!`); }

2. Пример на JavaScript в котором получим простые числа от 2 до 100:

// функция, определяющая является ли число простым const isPrime = (value) =>  const max = Math.floor(Math.sqrt(value)); for (let i = 2; i 

3. Пример, в котором вычислим целую и дробную часть числа :

const num = 7.21; // целая часть числа let intNum = Math.floor(num); // 7 // дробная часть числа let fractNum = num % 1; // 0.20999999999999996 // с точностью до 2 знаков fractNum = parseFloat((num % 1).toFixed(2)); // 0.21 // 2 способ fractNum = num - Math.floor(num); // 0.20999999999999996

В этом примере, получение целой части числа выполняется посредством Math.floor() , а дробной части с помощью получения остатка от деления на 1 или вычитания числа от его целой части.

4. Пример, в котором определим, делится ли число нацело , используя оператор % :

const num = 9; // если остаток от деления на 3 значения переменной num равен 0, то, да, число целое; иначе нет if (num % 3 === 0) { console.log(`Число ${num} делится на 3`); } else { console.log(`Число ${num} не делится на 3 без остатка`); }

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

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