Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   UpJump: Q&A :) (https://javascript.ru/forum/misc/14421-upjump-q.html)

UpJump 23.01.2011 17:57

<script>
var x = 5.4444444444444444449
var y = 5.6785069743950934609
x = x.toFixed(2);
y = y.toFixed(2);
x=x-0;
y=y-0;
document.write("Первое число : " +x+"<br>");
document.write("Второе число : " +y+"<br>");
var result = x+y;
document.write("Сумма : "+result);
</script>

Сумма выходит не совсем такая какая ожидается. Насколько я понимаю происходит округление. Как тут быть? Сумма-то не совпадает.:blink: Есть ли альтернативное "верное" решение?

x-yuri 23.01.2011 18:12

Цитата:

Сообщение от UpJump
x=x-0;y=y-0;

происходит преобразование строки в формат IEEE 754. При сложении тоже могут иметь место потери точности. Округление не происходит

Цитата:

Сообщение от UpJump
Как тут быть?

в данном сферическом случае, никак

UpJump 23.01.2011 18:22

Ясно. Слушай x-yuri, ты уже второй раз говоришь о "сферическом". А что это значит? Так для саморазвития.:)

Sweet 23.01.2011 19:02

Цитата:

Сообщение от UpJump
А что это значит? Так для саморазвития.

Я слышал анекдот про движение сферического коня в вакууме, но не помню его:)

Aetae 23.01.2011 19:05

http://lurkmore.ru/Сферический

UpJump 23.01.2011 19:57

как можно стопроцентов получить рандомное число с количеством цифр после десятичной точки к примеру 2?
То есть число.xx?
toFixed() не дал результата(выше спрашивал).
Пробывал так.
var x = (Math.random() - Math.random())*100;
x = (x.toString().substr(0,4))-0;

тоже ничего.

Aetae 23.01.2011 20:05

var max=100
alert( (Math.random()*max).toFixed(2) )

UpJump 23.01.2011 20:12

Нет. ты не понял. Я задавал вопрос выше на этой странице.http://javascript.ru/forum/misc/1442...html#post89307
Если я сделаю вычитание одного такого числа из другого то не всегда получу "правильный" результат.Надеюсь понятно.:)

Aetae 23.01.2011 20:20

Дык всё равно toFixed на резульат.

UpJump 23.01.2011 20:24

нет. меня интересует только чистое число с двумя цифрами после точки. Посмотри пример что я тебе указал. там результат не тот какой хотелось бы. А именно нужен 11.12.

x-yuri 23.01.2011 20:39

Цитата:

Сообщение от UpJump
А что это значит?

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

в финансовых вычислениях, например, используется arbitrary-precision arithmetic

но в большинстве реальных задач это не имеет смысла

а ты чего хочешь сделать?

UpJump 23.01.2011 20:57

это просто небольшая задачка для себя самого. смысл:
Я получаю пример в виде суммы из двух чисел. числа генерятся рандомно, причем цифры должны быть с дробной частью, но к примеру с двумя цифрами после точки. Далее вызывается prompt(). Я ввожу ответ. и он проверяется. И тут облом. оказывается ответ который я ввожу неверен. собственно это все. ничего для спасения мира:)
UPD
Пробывал даже так:
1)получить рандомное число
2)перевести его в строку
3).substr(0,4) этой строки
4)отнять от этой строки ноль. то есть перевести ее в число.

x-yuri 23.01.2011 22:18

Цитата:

Сообщение от UpJump
4)отнять от этой строки ноль. то есть перевести ее в число.

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

если ты хочешь решить эту задачу, либо поищи arbitrary-precision библиотеки, либо напиши свою

UpJump 23.01.2011 22:26

мдя.. жаль. ну все равно спс.

UpJump 25.01.2011 20:16

Собственно сообразил решение поставленной(самому себе:) ) сферической задачи.
sum = 0.1 + 0.2;
x = prompt("0.1 + 0.2 == ?")
if(sum == x)alert("true");else alert("false");

Естественно будет не 0.3 т.к. погрешность
alert(0.1 + 0.2);

Зато это можно обойти так.
sum = 0.1 + 0.2;
x = prompt("0.1 + 0.2 == ?")
if(sum-0.01<x&&x<sum+0.01)alert("true");else alert("false");

Как бы создав поле допустимой погрешности.
UPD
Естественно если мы введем ответ 2.999999999999 то результат тоже будет true. но для ответа до одной цифры после точки решение годится.

x-yuri 25.01.2011 21:29

собственно, это одно из правил при работе с числами с плавающей запятой: не использовать оператор ==

рони 26.01.2011 04:59

UpJump,
<script>
var x = 5.4444444444444444449;
var y = 5.6785069743950934609;
var f = 2;
x = x.toFixed(f);
y = y.toFixed(f);
document.write("Первое число : "+x+"<br>");
document.write("Второе число : "+y+"<br>");
var s=Math.pow(10,f);
var result = (x*s+y*s)/s;
document.write("Сумма : "+result);
</script>

Aetae 26.01.2011 05:05

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

Как-то так, имхо.
s=0.1+0.2;
alert(s)
s=+s.toFixed(10)
alert(s)

рони 26.01.2011 05:13

Aetae,
Приведи неработающий пример для моего варианта?

Aetae 26.01.2011 05:17

Цитата:

Сообщение от рони (Сообщение 89701)
Aetae,
Приведи неработающий пример для моего варианта?

Ты предлагаешь мне вручную подобрать? А если подумать?

Впрочем, простой цикл и Math.round() сделал это за меня:
<script>
var x = 70.40234624004941;
var y = 4.785769407478535;
var f = 2;
x = x.toFixed(f);
y = y.toFixed(f);
document.write("Первое число : "+x+"<br>");
document.write("Второе число : "+y+"<br>");
var s=Math.pow(10,f);
var result = (x*s+y*s)/s;
document.write("Сумма : "+result);
</script>
<br>
<script>
var x = 9.244540723646633;
var y = 71.35153269338788;
var f = 2;
x = x.toFixed(f);
y = y.toFixed(f);
document.write("Первое число : "+x+"<br>");
document.write("Второе число : "+y+"<br>");
var s=Math.pow(10,f);
var result = (x*s+y*s)/s;
document.write("Сумма : "+result);
</script>

рони 26.01.2011 05:52

Aetae, ок )))
<script>
var x = 70.40234624004941;
var y = 4.785769407478535;
var f = 2;
x = x.toFixed(f);
y = y.toFixed(f);
document.write("Первое число : "+x+"<br>");
document.write("Второе число : "+y+"<br>");
var s=Math.pow(10,f);
var result = (x*s+y*s).toFixed(0)/s;
document.write("Сумма : "+result);
</script>
<br>
<script>
var x = 9.244540723646633;
var y = 71.35153269338788;
var f = 2;
x = x.toFixed(f);
y = y.toFixed(f);
document.write("Первое число : "+x+"<br>");
document.write("Второе число : "+y+"<br>");
var s=Math.pow(10,f);
var result = (x*s+y*s).toFixed(0)/s;
document.write("Сумма : "+result);
</script>

http://javascript.ru/forum/css-html/...gleniem-2.html

x-yuri 26.01.2011 18:17

рони, а теперь расскажи, в каких условиях твое решение будет давать верный результат. И если ты не видишь проблему, то проблема в том, что строку '3' можно представить в виде числа без потерь точности, а строку '0.3' - нельзя

рони 26.01.2011 22:18

x-yuri,
Разве сумма в данном скрипте не верна?
<script>
var x = 100*Math.random();
var y = 100*Math.random();
var f = 2;
x = x.toFixed(f);
y = y.toFixed(f);
document.write("Первое число : "+x+"<br>");
document.write("Второе число : "+y+"<br>");
var s=Math.pow(10,f);
var result = (x*s+y*s).toFixed(0)/s;
document.write("Сумма : "+result);
</script>

x-yuri 26.01.2011 23:12

У меня нету времени проверять твой скрипт для всех возможных вариантов входных значений. А если бы Aetae не подобрал значения, с которыми не справляется твой предыдущий вариант, ты б так и думал, что предыдущий вариант рабочий (Aetae вся надежда на тебя :X)

рони 27.01.2011 00:49

x-yuri,
В нерабочем варианте было пропущено toFixed(0)
Вариант округления взят отсюда Math.floor проблема с округлением в тот раз против него у вас не было возражений, кроме подсказки более компактного варианта.

Aetae 27.01.2011 01:08

Я так и не понял зачем все эти надмозги.
Number.prototype.toNumFixed=function(n){return +this.toFixed(+n||15)}
alert((0.1+0.2).toNumFixed())

Этого достаточно чтоб избавиться от погрешности.

x-yuri 27.01.2011 02:10

Цитата:

Сообщение от рони
В нерабочем варианте было пропущено toFixed(0)

а что в этом варианте пропущено?

Цитата:

Сообщение от рони
в тот раз против него у вас не было возражений, кроме подсказки более компактного варианта.

Совершенству нет предела )))

Цитата:

Сообщение от Aetae
Я так и не понял зачем все эти надмозги.

для задачи UpJump твой вариант подходит (скорее всего, надо проверить). Но в следующем случае, например, уже не работает:
Number.prototype.toNumFixed=function(n){return +this.toFixed(+n||15)}
alert((0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 +0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1).toNumFixed())

просто если уж применять ваши решения, то хотелось бы знать, при каких условиях они работают. Хотя я уже приблизительно придумал, как это выяснить

Aetae 27.01.2011 02:53

Дык это понятно, погрешность накапливается. Для общего случая округление до 15 знаков - достаточно, чтоб наверняка - можно взять 10.

Естесно никто не застрахован от:
Number.prototype.toNumFixed=function(n){return +this.toFixed(+n||10)}
i=10000;
n=0
while(i--)n+=0.1
alert([n,n.toNumFixed()])

Но эт маловероятно в реальной практике.

Да и вообще по-хорошему нужно указывать вручную до какого знака округлять.

x-yuri 27.01.2011 03:22

Цитата:

Сообщение от Aetae
Но эт маловероятно в реальной практике.
Да и вообще по-хорошему нужно указывать вручную до какого знака округлять.

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

а вообще, мне уже просто интересно, как интерпретатор преобразовывает строку в число и наоборот. Например, при преобразовании в строку он похоже округляет до 16 знака
alert([0.30000000000000001, 0.30000000000000009])

т.е. он немного урезает точность и за счет этого не видно неточность преобразования строки в число. Но при всем при этом ходят слухи, что у double 16 (15.955) значащих цифр, что вводит меня в когнитивный диссонанс

UpJump 01.02.2011 13:55

Всем снова привет:)
Читаю Флэнагана. Есть у него похожий код.
var o = {};
alert(o == "object");

В чем подвох? разве тут нет объекта? Я понимаю что
var o = {};
alert(typeof o == "object");

будет проверять тип данных. Но что проверяется в первом случае?

x-yuri 01.02.2011 14:09

в первом случае объект сранивается со строкой. В каком разделе у него такой код?

UpJump 01.02.2011 14:21

Все само разрешилось. Извиняюсь за чухню которую написал. Недосмотрел код.

Aetae 01.02.2011 21:15

Вообще можно и так
alert({}=='[object Object]')

но так делать нельзя.)))

B@rmaley.e><e 01.02.2011 21:48

В данном случае будет просто вызван метод toString операнда. Примерно таким образом, ЕМНИП, рекомендуют проводить проверку на массив:
var arr = [];
alert(Object.prototype.toString.call(arr) === '[object Array]');

Aetae 01.02.2011 22:07

Эт ясно, только разные браузеры методом toString могут такой чухни понаписать) Если с object и array ещё нормально то dom элементы весьма разнятся.

UpJump 05.02.2011 19:19

Всем привет. Это снова я:write:
var str = 'hello "Java"';
alert(str.match(/a|"([^"]*)"/));

Собственно не понял почему не происходит выборка символа а в массив. Ведь при проверке текста с помощью к примеру
/x|y/
если найден x то y искаться уже не должен.

Kolyaj 05.02.2011 19:26

Цитата:

Сообщение от UpJump
если найден x то y искаться уже не должен.

В вашем случае сначала найден y, а x находится внутри y.

UpJump 05.02.2011 21:00

блин что-то все равно в голове не уляжеться. а как тогда изменить что бы вначале нашел а но не удаляя вторую часть условия?
("([^"])*")
То есть искать а. если не найдено то искать ("([^"])*")

UpJump 05.02.2011 21:09

Кажется понял.
var str = 'hello "Java"';
alert(str.match(/a|"([^"]*)"/));

При выборке он проверяет каждый символ в строке и для каждого символа выполняет условие или. То есть вначале он проверяет h(если символ соответствует первому условию то записывает в массив, если нет то проверяет второе условие) затем e и так далее. То есть по очередности для каждого символа, а не первое условие на всю строку а затем второе условие на всю строку. Я все правильно понял?

Aetae 05.02.2011 21:55

Цитата:

Сообщение от UpJump (Сообщение 91281)
Я все правильно понял?

Да.


Часовой пояс GMT +3, время: 05:52.