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

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

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

В разных культурах используются различные подходы к отображению чисел. Например, в одних культурах (в частности, в США, Великобритании) в качестве разделителя целой и дробной части применяется точка, а в других культурах — запятая. Аналогично разделителем между разрядами может служить как точка, так и запятая. И объект Intl.NumberFormat позволяет нам локализовать числительные под нужную культуру.

Конструктор Intl.NumberFormat может принимать два параметра:

Intl.NumberFormat([locales[, options]])

Параметр locales представляет код языка в формате BCP 47 или набор языковых кодов.

Параметр options представляет дополнительный набор опций:

  • localeMatcher : алгоритм поиска соответствий. Может принимать два значения: «lookup» и «best fit» . Значение по умолчанию — «best fit» .
  • compactDisplay : применяется, если параметр notation равен «compact» . Возможные значения: «long» и «short» (значение по умолчанию)
  • currency : задает валюту, которая применяется для форматирования. В качестве значения принимает код валюты в формате ISO 4217, например, «USD» (доллар США), «EUR» (евро) и т.д. Этот параметр необходимо обязательно указать, если параметр style имеет значение «currency» .
  • currencyDisplay : указывает, как отображать валюту. Возможные значения:
    • «symbol» : применяется символ валюты (например, € для евро). Значение по умолчанию
    • «narrowSymbol» : применяется сокращенное обозначение валюты (например, «$100» вместо «US$100»)
    • «code» : применяется код валюты
    • «name» : применяется локализованное название валюты (например, «dollar»)
    • «standard» : применяется для форматирования обычных чисел. Значение по умолчанию
    • «scientific» : возвращает порядок величины для форматируемого числа
    • «engineering» : возвращает значение в экспоненциальной нотации
    • «compact» : для представления экспоненциальной записи применяется строка
    • «auto» : знак отображается только для отрицательных чисел. Значение по умолчанию
    • «never» : знак никогда не отображается
    • «always» : знак отображается всегда
    • «exceptZero» : знак отображается для всех чисел, кроме нуля
    • «decimal» : для форматирования обычных чисел. Значение по умолчанию
    • «currency» : для форматирования валюты
    • «percent» : для форматирования процентов
    • «unit» : для форматирования единиц измерения
    • «long» : полная форма (например, 16 litres )
    • «short» : сокращенная форма (например, 16 l ). Значение по умолчанию
    • «narrow» : сжатая форма (например, 16l )

    Для форматирования числа объект Intl.NumberFormat предоставляет метод format() , в который передается форматируемое число и который возвращает отформатированное число в виде строки.

    Локализуем число 5500,67 на разные языки:

    const amount = 5500.67; const en = new Intl.NumberFormat("en").format(amount); const ru = new Intl.NumberFormat("ru").format(amount); const de = new Intl.NumberFormat("de").format(amount); console.log(en); // 5,500.67 console.log(ru); // 5 500,67 console.log(de); // 5.500,67

    По умолчанию для форматирования чисел применяется параметр . Также мы могли бы его явно применить:

    const amount = 5500.67; const ru = new Intl.NumberFormat("ru", ).format(amount); // то же самое, что и // const ru = new Intl.NumberFormat("ru").format(amount); console.log(ru); // 5 500,67

    Форматирование процентов

    В разных культурах может отличаться написание процентов. Для локализации процентов применяется значение

    const value = 0.851; const en = new Intl.NumberFormat("en", ).format(value); const ru = new Intl.NumberFormat("ru", ).format(value); const tr = new Intl.NumberFormat("tr", ).format(value); console.log(en); // 85% console.log(ru); // 85 % console.log(tr); // %85
    Вывод дробной части

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

    const value = 0.851; const en = new Intl.NumberFormat("en", ).format(value); const ru = new Intl.NumberFormat("ru", ).format(value); console.log(en); // 85.10% console.log(ru); // 85,10 %

    Форматирование валюты

    Для форматирования валюты применяется параметр style: «currency» , при этом также надо указать параметр currency , которому передается код валюты:

    const value = 85.1; const en = new Intl.NumberFormat("en", ).format(value); const ru = new Intl.NumberFormat("ru", ).format(value); const tr = new Intl.NumberFormat("tr", ).format(value); console.log(en); // $85.10 console.log(ru); // 85,10 $ console.log(tr); // $85,10

    Вывод нескольких валют:

    const value = 85.1; const usd = new Intl.NumberFormat("ru", ).format(value); const euro = new Intl.NumberFormat("ru", ).format(value); const rub = new Intl.NumberFormat("ru", ).format(value); console.log(usd); // 85,10 $ console.log(euro); // 85,10 € console.log(rub); // 85,10 ₽

    По умолчанию выводится символ валюты, однако значение currencyDisplay: «name» позволяет вывести локализованное название валюты:

    const value = 85; const usd = new Intl.NumberFormat("ru", ).format(value); const euro = new Intl.NumberFormat("ru", ).format(value); const rub = new Intl.NumberFormat("ru", ).format(value); console.log(usd); // 85 долларов США console.log(euro); // 85,00 евро console.log(rub); // 85,00 российского рубля

    Форматирование единиц измерения

    Для форматирования единиц измерения применяется значение style: «unit» . При этом также необходимо указать название единицы измерения с помощью параметра unit :

    const value = 85; const en = new Intl.NumberFormat("en", ).format(value); const ru = new Intl.NumberFormat("ru", ).format(value); const zh = new Intl.NumberFormat("zh", ).format(value); console.log(en); // 85 L console.log(ru); // 85 л console.log(zh); // 85升

    По умолчанию применяет сокращенная форма наименования валюты. С помощью значения unitDisplay: «long» можно задать вывод полного наименования:

    const value = 85; const longLiter = new Intl.NumberFormat("ru", ).format(value); const shortLiter = new Intl.NumberFormat("ru", ).format(value); console.log(longLiter); // 85 литров console.log(shortLiter); // 85 л

    Еще несколько примеров с форматированием разных единиц измерения:

    const value = 85; const kilobyte = new Intl.NumberFormat("ru", ).format(value); const meter = new Intl.NumberFormat("ru", ).format(value); const gram = new Intl.NumberFormat("ru", ).format(value); console.log(kilobyte); // 85 килобайт console.log(meter); // 85 метров console.log(gram); // 85 грамм

    Метод toLocaleString типа Number

    Стоит отметить, что у типа Number есть метод toLocaleString() , который принимает локаль и который локализует в эту локаль число:

    const num = 1007.56; console.log(num.toLocaleString("en")); // 1,007.56 console.log(num.toLocaleString("de")); // 1.007,56 console.log(num.toLocaleString("ru")); // 1 007,56

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

    МЕРОПРИЯТИЯ

    Хакатон GO.ALGO

    01 декабря Москва Онлайн Бесплатно

    Комментарии

    Популярные По порядку
    Не удалось загрузить комментарии.

    ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

    Лайфхак: в какой последовательности изучать JavaScript

    Огромный инструментарий JS и тонны материалов по нему. С чего начать? Расскажем, как изучать JavaScript, и предоставим полезные ссылки.

    13 ресурсов, чтобы выучить математику

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

    16 бесплатных книг по JavaScript

    Коллекция бесплатных электронных книг для тех, кто хочет изучить JavaScript. Книги предоставляются в различных цифровых форматах: PDF, EPUB, HTML и др.

    Math.round()

    Метод Math.round() возвращает число, округлённое к ближайшему целому.

    Синтаксис

    Math.round(x)

    Параметры

    Описание

    Если дробная часть числа больше, либо равна 0,5, аргумент будет округлён до ближайшего большего целого. Если дробная часть числа меньше 0,5, аргумент будет округлён до ближайшего меньшего целого.

    Поскольку метод round() является статическим методом объекта Math , вы всегда должны использовать его как Math.round() , а не пытаться вызывать метод на созданном экземпляре объекта Math (поскольку объект Math не является конструктором).

    Примеры

    Пример: использование метода Math.round()

    // Вернёт значение 20 x = Math.round(20.49); // Вернёт значение 21 x = Math.round(20.5); // Вернёт значение -20 x = Math.round(-20.5); // Вернёт значение -21 x = Math.round(-20.51); // Вернёт значение 1 (!) // Обратите внимание на ошибку округления из-за неточности арифметики с плавающей запятой // Сравните этот результат с результатом Math.round(1.005, -2) из следующего примера x = Math.round(1.005 * 100) / 100; 

    Пример: корректировка округления десятичных дробей

    // Замыкание (function ()  /** * Корректировка округления десятичных дробей. * * @param type Тип корректировки. * @param value Число. * @param exp Показатель степени (десятичный логарифм основания корректировки). * @returns Скорректированное значение. */ function decimalAdjust(type, value, exp)  // Если степень не определена, либо равна нулю. if (typeof exp === "undefined" || +exp === 0)  return Math[type](value); > value = +value; exp = +exp; // Если значение не является числом, либо степень не является целым числом. if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0))  return NaN; > // Сдвиг разрядов value = value.toString().split("e"); value = Math[type](+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp))); // Обратный сдвиг value = value.toString().split("e"); return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp)); > // Десятичное округление к ближайшему if (!Math.round10)  Math.round10 = function (value, exp)  return decimalAdjust("round", value, exp); >; > // Десятичное округление вниз if (!Math.floor10)  Math.floor10 = function (value, exp)  return decimalAdjust("floor", value, exp); >; > // Десятичное округление вверх if (!Math.ceil10)  Math.ceil10 = function (value, exp)  return decimalAdjust("ceil", value, exp); >; > >)(); // Округление к ближайшему Math.round10(55.55, -1); // 55.6 Math.round10(55.549, -1); // 55.5 Math.round10(55, 1); // 60 Math.round10(54.9, 1); // 50 Math.round10(-55.55, -1); // -55.5 Math.round10(-55.551, -1); // -55.6 Math.round10(-55, 1); // -50 Math.round10(-55.1, 1); // -60 Math.round10(1.005, -2); // 1.01 -- сравните этот результат с результатом Math.round(1.005*100)/100 выше // Округление вниз Math.floor10(55.59, -1); // 55.5 Math.floor10(59, 1); // 50 Math.floor10(-55.51, -1); // -55.6 Math.floor10(-51, 1); // -60 // Округление вверх Math.ceil10(55.51, -1); // 55.6 Math.ceil10(51, 1); // 60 Math.ceil10(-55.59, -1); // -55.5 Math.ceil10(-59, 1); // -50 

    Спецификации

    Specification
    ECMAScript Language Specification
    # sec-math.round

    Совместимость с браузерами

    BCD tables only load in the browser

    Смотрите также

    • Math.abs()
    • Math.ceil()
    • Math.floor()
    • Math.sign() Экспериментальная возможность
    • Math.trunc() Экспериментальная возможность

    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х битный, т.ч. ты меня не испугал.

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

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