Я тут подахренел немного.
Сделали мы портфели на смартлабе (
тут). Вот я вбиываю в портфель покупку USDRUB по 56,45.
(я действительно там покупал баксы в мае).
Бах! А у меня в таблице тут же вбитое число отражается как 56,449999999999996.
Программист мне сказал, что НЕВОЗМОЖНО отражать число 56,45 как 56,45, а можно его только отражать как 56,449999999999996.
И на мои уговоры что-то с этим поделать посоветовал мне пойти
поучить матчасть.
Собрали мы учёный совет. начали думать. Несколько дней думали, так и не нашли решения.
В процессе обсуждения звучали такие слова как longint, мантисса, varchar,10^n в нужной степени, операции без радикалов и т.д.
Проблема в том, что число знаков после запятой может быть и 5 (для некоторых акций).
Поэтому просто округлить все числа до 2 знаков после запятой не получится.
Как изящно выйти из ситуации?
Но для вас, мне кажется, подойдет аналог «мягкого» округления. В R, например, это функция signif(). В других языках — надо смотреть.
В R есть встроенная функция:
signif(56.4499999996) = 56.45
Реализацию на других языках можно загуглить, пример:
stackoverflow.com/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits
Смотря какой язык. Вообще-то, тип данных Money есть. Decimal тоже подходит. Пример: http://support.sas.com/kb/51/034.html.
пусть делает printf("%.2f", num);
всё номано будет.
весь мир живёт с этим и норм, а он не может.
Vitty, на самом деле даже в этом случае можно обойти округлением до заданной точности.
более чем 18 значных чисел (18 значимых цифр) на смартлабе не будет, что покрывается стандартным double.
у меня на эту тему есть своя прохладная былина
stackoverflow.com/questions/24599498/rounding-double-strangeness
она немного другая, про целые числа, казалось бы, но смысл и причина у ней теже.
а есть ТГК-2 с ценой 0.001655
и одно надо показывать 6 знаков после запятой а другое — тока 2
вы же отображаете разные цены для разных акций. ну будете отображать разные цены для разных акций с разной точностью.
сам работаю в IT, но иногда хренею от своих коллег.
1) Где-то уже реализована это и показывает -> значит решение есть.
2) Лот, кол-во акции, цена, бид, аск, в конце концов справочник можно завести на каждую акцию, в котором хранить разрядность....
Тимофей, пушай своего прогера, ставь задачу — у других это сделано.
Тимофей Мартынов,
имхо дизайн сайта — местами, вырви глаз.
У меня вот так лента выглядит -
www.dropbox.com/s/n3b660o84nzmcnr/Screenshot%202017-06-28%2020.28.23.png?dl=0
могу докинуть CSS, если интересно
По делу: эта проблема существует, но Ваш программист ЭТО ЯВНО ЗАГНУЛ. Ближайшее представление указанного Вами числа:
5.6450000762939453125E1, то есть 56.450000776.....
Проверка тут:
www.binaryconvert.com
С такой проблемой сталкиваются инженеры из многих областей, и в трейдинге тоже. ИМЕННО ПОЭТОМУ в «финансовом» языке программирования Python есть средства для ЛЮБОЙ БОЛЬШОЙ ТОЧНОСТИ чисел.
Такие средства есть и в языке Си (++) путём применения специальных библиотек «arbitrary precision» типа MPFR.
Павел Голобородько (сидя в Японии) ведёт такой проект несколько лет:
www.holoborodko.com/pavel/mpfr/#intro
bitbucket.org/advanpix/mpreal/
Решение для Вашего случая — их несколько: например хранить такие данные в формате String, а для любых манипуляций тут же преобразовывать их в double (float), а затем показывать результат в ОКРУГЛЁННОМ ВИДЕ — с заранее заданной точностью. Проблема будет в том, чтобы муторно и скучно задавать уровень требуемый точности для всех ВЫВОДИМЫХ полей.
Копая далее математику для финансов Вы будете ещё боьше удивляться почему мир до сих пор не рухнул, если всё (все формулы) рассчитывается по стандарту IEEE754.
Такие проблемы могут возникать у инженеров в самых неожиданных местах.
Я писал об этом на форуме MQL5:
www.mql5.com/ru/forum/165397/page5
Даже при вычислении казалось бы простого полинома — для разных инженерных целей:
? = (333.75 — a2)b6 + a2 (11a2 b2 — 121b4 — 2) + 5.5b8 + a/(2b).
Из всех компиляторов Си только старый Borland может использовать — хранить и вычислять — все числа в формате 80 бит, используя всю точность процессора. Все остальные режут числовые слова до 64 бит. В Python используется встроенная бибилиотека повышенной точности, которая считает ПОБИТОВО все нужные операции с точностью 128 бит, и конечно делает это в 50-100 раз медленнее. Но в инженерии и финансах лучше медленее чем платить потом за рухнувший мост или за неправильные проценты с бондов, которые рассчитываются ПОСУТОЧНО с сумм типа 200 миллиардов долларов.
В моей личной практике был случай когда баланс областного банка свалился из-за того, что неумёха программист не учёл что-то типа 18...19-разрядной десятичной точности большой суммы баланса области в копейках (купоно-гривня была около 5000 за доллар).
Кстати Джеймс Саймонс из RenTec в одном из интервью сказал, что ЛУЧШЕ всех у него получается у АСТРОФИЗИКОВ.
У них нет проблем с пониманием как точно (насколько высоко точно) требуется высчитывать внутреннюю структуру ценовых рядов.
По Вашему случаю — я предложил наименее затратный и наиболее гибкий метод. Вы всегда сможете его потом заменить/поменять. прикрутить другой движок для расчётов, третий движок для отображения и тому подобное. Это профессиональный подход. Все остальные советы типа «про округление» загонят Вас чуть попозже в угол. И это будет негибко.
Даже в разных версиях компиляторов «от Микрософт» числа округляются по-разному, поэтому там есть опции компилятора типа /fp-precise. Лично я давно использую свою собственную функцию округления double.
Скажите о какой именно «разной точности» идёт речь? О полях в таблицах? Их можно по string хранить как угодно и преобразовывать тоже как угодно. Да, конечно, придётся написать 5-8 подпрограмм проверки ввода и конвертации в String данных. Уверяю Вас, в больших базах типа Oracle именно так и делается. Иначе не получится ни надёжности и цельности данных, ни точности. Там это встроено, а Вам придётся это написать самим. Вот и вся разница. Но Вы же профи, Тимофей. Ну так принимайте в работу проверенные методы профи.
Да, ещё снизится скорость лопачения данных. Но это же не проблема, не так ли?
msdn.microsoft.com/ru-ru/library/ms131275(v=vs.110).aspx
Акция, насколько я понимаю, описана классом. Ну так введите параметр — «разрядность».
или чего-нибудь ещё… покрепче… дать…
Ну так и округляйте до 5 знаков. При этом варианты с числом знаков 4, 3,… тоже придут в норму. Например, 56,449999999999996 округлится до 56,45000. Если требуется отображать именно 56,45, то придется число знаков для каждого типа хранить.
P.s. Или изначально хранить числа в строках.
P.p.s. Максимум знаков после точки 5? Тогда можно умножать на 10000 и хранить в виде целых чисел.
считаешь % до которого хочешь округлить. Например, это 0,01%. Берешь цену актива, считаешь этот процент. Например цена 100, тогда шаг при заданной точности 0,01.
Дальше считаешь число цифр после запятой. В питоне, например это можно сделать так, если наше число точности n.
str(n).split(',')[-1].count('0')+1
или лучше +2 с запасом.
1. округлять по минимальному шагу цены для фьючерсов самое оно.
2. так же есть параметр «точность», показывает сколько знаков после запятой используется в инструменте.
не знаю как с буржуйским рынками а с нашими всё прекрасно округляется и ничего лишнего не рисуется.
программист скорей всего ваш, изначально этот момент не продумал, а теперь лень все формы переделывать.
Правда придется хранить 2 числа (числитель и знаменатель), но зато не будет копиться ошибка при вычислениях - все операции проводите с дробью, пользователю отображаете округленный результат.
22/7 подходит
56.45 (4 знака, в начале числа нет нулей)
0.001655 (3 нуля в начале числа, дальше 4 знака после нулей)
Изящно все дробные числа хранить как целые, плюс в отдельном поле хранить точность.
То есть 56,45 хранить как 5645 и рядом число 2. Отображать ессно как 56,45 везде.
Тип данных float не предназначен для финансовых расчетов.
Все просто.
Если в некоторых акциях до 5-ти знаков после запятой, то и округляйте до пятого знака. Остальные сами округлятся.
56,449999999999996 = 56,44999 +0.00001 = 56,45
Либо до 8-го… результат будет тот же. А программист какбэ удивляет…
1) Использовать тип Decimal, Money, Короче тот который использует для хранения BCD формат.
2) Для каждого инструмента ввести хранить шаг цены — для всех валют обычно 4 знака, бонды и акции — обычно 6.
КАЖДЫЙ ДЕНЬ В ТЮРЬМУ ЗАВОЗЯТ -10 ЗАКЛЮЧЕННЫХ
ПРИ НЕХВАТКЕ ЗАКЛЮЧЕННЫХ — ПРОИСХОДИТ ОТКАТ К СОСТОЯНИЮ В ПРОШЛОМ МЕСЯЦЕ
ЗЕК-ВЕТЕРАН, ПОЛУЧИВШИЙ ТАКИМ ОБРАЗОМ 50 ХОДОК, ТРАНСФОРМИРУЕТСЯ В ОФИЦЕРА.
ЕСЛИ ОФИЦЕРОВ БОЛЬШЕ, ЧЕМ ЗЕКОВ, ТО ВЕСЬ ПЕРСОНАЛ СТАНОВИТСЯ ЗАКЛЮЧЕННЫМИ
У Вас ведь есть инфа по всем акциям с указанием шага цены?
Перед выводом округлять до шага цены.
Например, ШЦ = 0.01 --> выводить с точностью до 2-х знаков.
Если ШЦ = 0.0005 --> выводить с точностью до 4-х знаков.
Ещё в сишарп отлично работает что-то типа:
double roundedPx = PriceStep * Math.Round(px / PriceStep);
После такого преобразования подобные проблемы точности выравниваются.
- На входе 0,314, округляем до двух, получаем 0,31. Ура, Круто. А если шаг торгов 0,05? :-) Это касается и любителя предлагать printf("%.2f", num); — и типо все номано будет :-) Любитель Оракла, округли 0,359 до двух разрядов мега средствами если шаг 0,05 и он еще и варьируется ;-)
- Для любителя стрингов — мелькал тут, а проделай ка такую операцию хотя бы с одной акцией как ты советовал, если при считывании Стринга в дабл ты получить можешь для одного SECCODE 127, ;127,1; 127,11 ;-)
- Можно намоделировать массу примеров когда позиция, к примеру тейк профит будет при разных вариациях математического или бухгалтерского округления выдавать «шляпу».
Сам недавно решал эту проблему. Стандартные округления тут не подойдут, потому как помимо количества знаков после запятой есть еще и шаг торговли а он может быть для одного количества после запятой разным, поэтому формулы тут нет. И нагуглить «легко» не получится, т.к. это округление специфичное. Поэтому писаки сверху пальцем в небо тычут, тк результатом округления может стать х, ххх1 что не будет в некоторых случаях удовлетворять шагу торгов либо x,xxx5, что не позволит тебе закрыть позицию там где бы ты хотел. Поэтому, все советы которые предлагают для старта брать число СЖИГАЙ, по числу тут ничего не поймешь, для старта надо брать код бумаги.1. Необходимо формировать массив (к примеру) по бумагам, загрузить его легко, в Квике есть к примеру текущая таблица параметров содержащая, Код площадки, Код бумаги, количество знаков после запятой, шаг. Вот такой вот вид у нее:+МосЭнерго,TQBR,MSNG,,52848350,,2.3120,,,,,0.0000,0.0000,,,2079,,,1000,,,AGRO-гдр,TQBR,AGRO,,17453854,,610,,,,,0,0,,,439,,,1,,,Polymetal,TQBR,POLY,,38150043,,728.5,,,,,0.0,0.0,,,1681,,,1,,, Далее делай с ней что хочешь, парси а потом хош в массив загрузи и поиском по нему бегай, хош бегай поиском сразу по файлу(это нехорошо).2. Пишите функцию которой отправляете Площадку, Код бумаги, число а она возвращает число необходимое для подстановки по параметрам из массива. Пишется все за один рабочий день, два часа кода, 6 часов тестов :-). Можно и без площадки, я передаю ее на всякий случай, мало ли SECCODE совпадет с каким то на амер бирже. У меня ежесекундно тащатся порядка 120 инструментов, на каждом по 3 таймфрейма (итого 360 файлов), поиск и подстановка нужных чисел занимает для всей этой фермы секунды (использую массив). 2 ядра на сервере не быстрых и 2 Гб оперативки, диски обычные.
PS. Привет ребятам с Финама отвечающим за котировки. Откройте хотя бы один день то что вы выгружаете по Татнефти.Но спасибо Вам за информацию :-) И за знания которые пришлось приобрести. Что делать с программистом я не знаю, но совета что делать с ним и не спрашивали.
Возможно ты его не так уговариваешь. намекни что за такое и уволить бездельника можно! )
Кстати может это знак что нужно продавать а не покупать? )