Почему (1 + Number.MIN_VALUE) равно 1?

Я заметил, что они оцениваются как true:

  • (1 + Number.MIN_VALUE) === 1

  • Object.is(1 + Number.MIN_VALUE, 1)

Из документации :

Свойство статических данных Number.MIN_VALUE представляет наименьшее положительное числовое значение, которое можно представить в JavaScript.

Мои вопросы:

  1. Поскольку Number.MIN_VALUE не равно нулю, почему прибавление его к заданному числу не приводит к получению другого числа?

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

Интересный вопрос! У меня нет ответа в голове, но я бы начал с понимания того, как представлены числа. Точность чисел снижается по мере удаления от 0. Возможно, уже при 1 точности недостаточно, чтобы различить различия MIN_VALUE.. Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

Antti_M 09.05.2024 15:41

См.: stackoverflow.com/questions/17849101/…

user2652134 09.05.2024 15:41

Поскольку причина (1.) одинакова для всех языков, использующих ieee 475, вы можете посмотреть stackoverflow.com/questions/41317661/…

t.niese 09.05.2024 15:43

Отвечает ли это на ваш вопрос? Математика с плавающей запятой не работает?

derpirscher 09.05.2024 15:44

@derpirscher Нет, я знаю, что математика с плавающей запятой странная. Мне было интересно, почему Number.MIN_VALUE в некоторых случаях оказывается эквивалентным нулю. Это из-за странностей с плавающей запятой, но это другой вопрос.

RobertAKARobin 09.05.2024 15:55
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
5
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

По вашим вопросам:

Для более надежных сравнений из-за особенностей внутреннего представления с плавающей запятой вы можете сравнивать следующим образом:

const x = 0.1, y = 0.2, expectedResult = 0.3;

function equalNumber(a,b) {
  return Math.abs(a - b) < Number.EPSILON;
}

console.info('===', x + y === expectedResult);

console.info('equalNumber', equalNumber((x+y), expectedResult));

Что касается вашего второго вопроса, то число, которое вы запрашиваете, — Number.EPSILON.

Обратите внимание, что с увеличением чисел точность снижается, поэтому это не очень надежный способ проверки равенства. Для получения дополнительной информации прочитайте ответ @Amadan или прочитайте на MDN.

Спасибо! Я просто проделал небольшой цикл, чтобы найти наименьшее число, которое можно прибавить к 1, и, конечно же, результатом было то же значение, что и Number.EPSILON, о котором я до сих пор не знал. let last = 0, test = 1; while (1 + test !== 1) { last = test; test /= 2; } console.info(last);

RobertAKARobin 09.05.2024 15:53
return (a - b) < Number.EPSILON; не является общим решением для сравнения чисел с плавающей запятой. Как сравнивать числа с плавающей запятой всегда зависит от варианта использования. Кроме того, добавление Number.EPSILON к числу не гарантирует, что оно изменится, и это не самое маленькое число, которое приведет к изменению (это верно только при добавлении к 1).
t.niese 09.05.2024 15:54

@t.niese Не стесняйтесь дать более точный и исчерпывающий ответ. Я с нетерпением жду, что!

connexo 09.05.2024 16:25

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

Я не уверен, что существует элегантный способ сделать это в JavaScript. К счастью, способ представления чисел с плавающей запятой одинаков в большинстве языков программирования, поэтому мы можем найти ответ в другом месте. В Python, например, есть метод, который сообщает следующее представимое число с плавающей запятой после заданного в заданном направлении. (C тоже так делает; Python на самом деле просто привязывается к C.) Итак, первое число с плавающей запятой после 1.0 (в направлении положительной бесконечности):

import math

math.nextafter(1.0, math.inf)
# => 1.0000000000000002

Наименьшее число, которое вы можете добавить к 1.0, чтобы изменить его, должно составлять где-то около половины разницы из-за округления:

x1 = (math.nextafter(1.0, math.inf) - 1.0) / 2.0
x1
# => 1.1102230246251565e-16
1.0 + x1
# => 1.0

x2 = math.nextafter(x1, math.inf)
x2
# => 1.1102230246251568e-16
1.0 + x2
# => 1.0000000000000002

Таким образом, x1 и x2 являются соседними числами с плавающей запятой (т. е. между ними нет другого числа с плавающей запятой), где одно слишком мало, чтобы иметь значение в дополнение к 1.0, а другого достаточно.

Мы можем вернуть его в JavaScript, чтобы подтвердить:

x1 = 1.1102230246251565e-16
x2 = 1.1102230246251568e-16

console.info(`1.0 + ${x1} = ${1.0 + x1}`)
console.info(`1.0 + ${x2} = ${1.0 + x2}`)

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

К сожалению, в JavaScript нет метода nextafter. На вопрос Быстрая функция nextafter в JavaScript есть пара ответов, которые претендуют на ее реализацию, но я недостаточно силен математически, чтобы ручаться за их правильность.

Из вышеизложенного также видно, что наименьшее число, которое можно добавить к 1.0, чтобы изменить ситуацию, на самом деле не Number.EPSILON, а чуть больше половины, и это специфично для случая 1.0. Number.EPSILON достаточно велико, чтобы изменить 2.0000000000000004, следующее число с плавающей запятой после 2.0:

n1 = 2.0
n2 = 2.0000000000000004

console.info(`${n1} + Number.EPSILON = ${n1 + Number.EPSILON}`)
console.info(`${n2} + Number.EPSILON = ${n2 + Number.EPSILON}`)

Другие вопросы по теме