при marketBuyPrice = 0 неправильно работает .. (но возможно конечно у тебя всегда marketBuyPrice > 0 по ТЗ) R3>Забей. Вон рабочий вариант: http://rsdn.org/forum/dotnet/8360983.1
Здравствуйте, Real 3L0, Вы писали:
R3>Нее, только decimal. Там после запятой много цифр может быть.
В цене? У цены всегда есть минимальный шаг. Вот он пусть и будет decimal. А все операции с торговлей делаю над целыми числами шагов. Т.е. цена выражается целым числом, а представление, для визуализации или торгового апи, — decimal.
Мы тут это уже как-то обсуждали. Хранить поток сделок с ценой, укладывающейся в один байт со знаком (разница с предыдущей в количестве шагов), это одно удовольствие.
И вот ни разу не пригодилась цена в пол-шага. В индикаторах в математике использую double, он быстрее в разы, а абсолютная точность в индикаторах не требуется. Тоже сначала на decimal всё было, потом разок как профильнул — так сразу и отрефачил всё.
xma>можешь погонять тут random, запуская код xma>[cut=код с random] xma>https://dotnetfiddle.net/
Ты свой туда же подложи, и посмотрим, это код не работает, или ты просто эксплойтишь ограниченное количество знаков после точки в decimal.
Так-то шагов цены в виде периодической бесконечной дроби не бывает. Даже в крипте с меняющимся шагом.
Здравствуйте, Xander Zerge, Вы писали: XZ>Ты свой туда же подложи, и посмотрим, это код не работает,
я согласен что мой код слегка чаще выдаёт — отличный от идеального результат, и что у Serge_Novikoff — оптимальнее код ..
но, также как и в моём коде из за проблем точности, также и в коде Serge_Novikoff — нередко возникает неверный (точнее не идеальный) результат (при чём весьма часто именно тот же неверный что и мой код выдаёт) .. XZ>или ты просто эксплойтишь ограниченное количество знаков после точки в decimal.
я ничё не эксплойтю, тут проблема в самой точности хранения чисел в decimal и результатов проводимых операций над ними .. XZ>Так-то шагов цены в виде периодической бесконечной дроби не бывает. Даже в крипте с меняющимся шагом.
ну как правильно говорит Xander Zerge — тут возможно стоит если нужна точность смотреть в сторону напр., (условного) "BigInteger" и тому подобных (которые обычно используют для банковских операций, для того чтобы не терять точность на float'ах или даже double'ах)
(могу предположить что в виде fixed point)
вот код рандома с моими старыми test_optimal (и test_optimal2), если уж тебе так интересно их по тестить ..
Здравствуйте, Xander Zerge, Вы писали: XZ>Ты свой туда же подложи, и посмотрим, это код не работает, или ты просто эксплойтишь ограниченное количество знаков после точки в decimal.
я решил задачу (test_optimal2), теперь верно абсолютно всегда — даже когда test_optimal_Serge_Novikoff неверно ..
проверял для overwriteMinStep > 0 и marketBuyPrice >= 0,
P.S.:
если опять возникнут какие либо проблемы, то регулируйте степень (Pow) десятки в DecimalEpsilon — с 6 до нужного большего числа .. (чтобы увеличить делитель единицы), работоспособный минимум на данных тестах 1/(10^24)
Здравствуйте, Xander Zerge, Вы писали: XZ>Ты свой туда же подложи, и посмотрим, это код не работает, или ты просто эксплойтишь ограниченное количество знаков после точки в decimal.
пофиксил также метод Serge Novikoff в виде test_optimal_Serge_Novikoff_fixed — теперь и он работает идеально
test_optimal_Serge_Novikoff — это не пофикшенный (криво работающий) метод Serge Novikoff'а .. (для наглядности оставил, для сравнения результатов работы),
test_optimal2 — это ещё в прошлый раз пофикшенный мой метод (также работающий идеально) ..
P.S.:
проверено для overwriteMinStep > 0 и marketBuyPrice >= 0,
(если нужна бОльшая точность, то регулируйте степень (Pow) десятки в DecimalEpsilon, (для делителя))
P.S.2:
Xander Zerge, в целом у тебя тоже верная и интересная идея, и как и у меня тут лишь точность сравнения (по окрестностям) с погрешностью DecimalEpsilon обыграть надо было .. (если не ошибаюсь, то я эту фишку сравнения чисел с плавающей точкой изначально вроде в книге Андре Ламота подчерпнул, более 15 лет назад — на сравнении float с нулём)
P.S.3:
кстате, про сравнение decimal с нулём — так и знал что надо тоже через окрестности DecimalEpsilon, иначе (проверил) глючит (на мелких числах) ..
(уже поправил),
общая точность DecimalEpsilon по умолчанию задана как 1/(10^6), т.е. одна миллионная ..
Да.
Пример: https://www.moex.com/ru/issue.aspx?code=vtbr
Рыночная цена (2), рублей 0,020005
XZ> У цены всегда есть минимальный шаг. Вот он пусть и будет decimal. А все операции с торговлей делаю над целыми числами шагов. Т.е. цена выражается целым числом, а представление, для визуализации или торгового апи, — decimal. XZ>Мы тут это уже как-то обсуждали. Хранить поток сделок с ценой, укладывающейся в один байт со знаком (разница с предыдущей в количестве шагов), это одно удовольствие.
Не понял. Эта идея реализована в твоём примере? Я ещё не разобрал твоё решение.
Здравствуйте, Real 3L0, Вы писали:
R3>Пример: https://www.moex.com/ru/issue.aspx?code=vtbr R3>Рыночная цена (2), рублей 0,020005
Это много? Шаг цены 0.000005 р. Всё равно оперируешь целым количеством шагов. В этой цене их 4000 и это не много. Скажем, в цене Сбера 100р. — 10000 шагов.
R3>Не понял. Эта идея реализована в твоём примере? Я ещё не разобрал твоё решение.
Да, в моём примере мин-макс цены определяются в целых числах шагов. А в результат уже идёт номер шага, умноженный на шаг.
Здравствуйте, Real 3L0, Вы писали:
R3>flag_test_optimal2 = True
это мой код — всегда верно
R3>flag_test_Serge_Novikoff = False
это код от Serge_Novikoff — часто выдаёт неверный результат
R3>flag_test_Serge_Novikoff_fixed = True
это пофикшенный мною код (посредством использования DecimalEpsilon) от Serge_Novikoff — теперь тоже всегда верно
R3>Эээ, что-то это мне не нравится. R3>Девятки эти в периоде. Из-за них и значения кажутся не совпадающими, пока не округлишь.
какие проблемы, "Вася" — округляй до двух знаков после запятой результат .. (если тебе так надо)
R3>Рассчитывать DecimalEpsilon — это как? Под каждый набор входящих атрибутов?
DecimalEpsilon — это точность сравнения например с нулем или около окрестностей точки (числа с плавающей точкой),
ну т.е. (например) если DecimalEpsilon = 0.000001, то все числа по модулю меньшие этого числа считаются нулём ..
R3>У Serge_Novikoff более понятный алгоритм (если без DecimalEpsilon)
так он у него неверный смотри что он (ret_opt_Serge_Novikoff) выдаёт (в твоей цитате) в сравнении с твоими оригинальным кодом (ret_original)
мой код (ret_opt2) и пофикшенный от Serge_Novikoff c DecimalEpsilon выдают результат (ret_opt_Serge_Novikoff_fixed) с точностью неотличимой от оригинала (ret_original) до одной миллионной (можно повысить или понизить точность, уменьшая или увеличивая значение константы DecimalEpsilon)
P.S.:
Real 3L0, могу подробнее объяснить свой алгоритм если интересно :
напр., при исходных значениях 90.1 и 0.2 получаем 90.2, (т.е. 90+0.2),
а проверка (if) в конце сделано чтобы когда напр. при исходных значениях 90 и 0.2, из за того что всё разделится нацело и до (if) получим 90.2 (90+0.2), а результат должен быть просто 90 ..
(поэтому то что получили до (if) проверяем на равенство сумме исходных чисел (marketBuyPrice + overwriteMinStep), если равно (с учётом окрестностей, т.е. с отклонением до плюс минус DecimalEpsilon) то значит из результата нужно вычесть overwriteMinStep (т.е. в нашем примере 0.2))
K>>так наверно даже быстрее посчитает, без ветвлений, но суть та же K>>
R3>Аналогично. R3>Но оба варианта — близко.
А не осталось входных данных, на которых не совпадает?
А то даже интересно стало.
Как по мне, так обсуждаемые здесь варианты — то же самое, что у меня.
Только там из Floor вручную делается Ceiling.
Здравствуйте, Real 3L0, Вы писали:
R3>Это цены, тут нет 9-к в периоде.
внутреннее представление чисел с плавающей точкой знаешь ли может быть весьма своеобразным, по мере проведения вычислений (так что рекомендую не воротить носом, а использовать безопасный код)
R3>У меня такое ощущение, что у вас одинаковые по смыслу алгортимы.
ну я сначала прибавляю единицу, а потом проверяю чтобы не совпадало с "(marketBuyPrice + overwriteMinStep)",
напр., 90 и 0.2, результат 90.2 (до проверки и вычета 0.2 (overwriteMinStep))
напр., 90.1 и 0.2, результат 90.2 (до проверки, вычет не нужен)
а он сначала проверяет что результат точно меньше marketBuyPrice, а потом уже прибавляет единицу
напр., 90 и 0.2, результат 90 (проверка на 90 < 90 не проходит, и к коэффициенту (множителя minStep) единица не прибавляется)
напр., 90.1 и 0.2, результат 90 (проверка на 90 < 90.1 проходит, и к коэффициенту (множителя minStep) прибавляется единица)
Здравствуйте, karbofos42, Вы писали:
K>А не осталось входных данных, на которых не совпадает? K>А то даже интересно стало.
Теперь мне интересно стало, потому что расхождений больше не вижу!
Странно я проглючил.
K>Как по мне, так обсуждаемые здесь варианты — то же самое, что у меня. K>Только там из Floor вручную делается Ceiling.
Получается, что твоя одна строка
var mediumPrice3 = decimal.Ceiling(marketBuyPrice / overwriteMinStep.Value) * overwriteMinStep.Value;
это тоже самое, что
var imin = (int)(marketBuyPrice / overwriteMinStep);
if (overwriteMinStep * imin < marketBuyPrice)
++imin;
Здравствуйте, Real 3L0, Вы писали:
R3>Получается, что твоя одна строка
... R3>это тоже самое, что
... R3>?
Ну, математически одно и то же по сути.
Ceiling — округление до целого вверх.
90.2 превращается в 91. 90.0 остаётся 90.
В итоге через этот метод определяется число шагов и умножается на размер шага.
В альтернативном варианте делается округление вниз (отсекается дробная часть).
В итоге 90.2 превращается в 90. Потом проверяется, что если всё же этого не хватит (минимальная цена не кратна шагу), то добавляется 91-й шаг.
Но вся эта математика с плавающей запятой очень плавающая из-за особенностей реализации, поэтому фактический результат может быть разный, но в рамках погрешности )