Декодер в S/360 способен сразу определить длину текущей команды
Ну так я образчик такого подхода и предлагал.
А в IA-32 затраты на то же самое будут кошмарными (собственно, они такие и есть).
На самом деле не настолько. Его уже достаточно хорошо вылизали. Есть форумы, где вопрос "насколько неровность кодировки в x86 дороже ARM?" (ARM берётся, потому что много где, включая Apple) обжевали со всех сторон. Усреднённый вывод - всё это максимум пара процентов от суммарных затрат процессора. И это, да, даже с тем кошмаром, что в x86. Ну а если что-то поаккуратнее - так и с микроскопом не будет рассмотреть.
Если вы твёрдо знаете, что это "кошмарные" выливается в какие-то конкретные цифры, а не просто личные впечатления "ужас-ужас!" - поделитесь ссылкой. Мне будет крайне интересно.
Полная sequential consistency. В PoO ни слова про модель памяти в плане синхронизации между разными процессорами (ядрами). Барьерных команд нет, барьеры из какого-нибудь C просто компилируются в ноль команд. Значит, реального OoO нету - даже такого с TSO, как в x86.
Ну а 64-разрядный от AMD в этом смысле выглядит, пожалуй, даже хуже: полной совместимости они не сохранили (в частности, выпилили поддержку V86 и некоторые команды), а система кодирования стала ещё уродливей.
По этому поводу уже высказался не один раз - нищие, которые поставили всё на один кон и выиграли, и при этом имели минимум ресурсов - обвинять их бесполезно. В конце концов, могло быть и хуже (вспоминаем IA64).
Как по мне, стоило бы делать полностью новую кодировку, сохранив лишь "идеологию" системы команд, ну а совместимость обеспечивать за счёт режима совместимости
Ну цена в полтора раза по длине для пользователей SystemZ не страшна.
Меня в этом плане больше удручает модель OoO и его работы с памятью, вот тут потеря производительности может быть в разы. Но, вероятно, это тоже для данного сегмента рынка вполне приемлемо.
Ну так и в S/360 с потомками декодер по полусловам будет в большинстве случаев находить ошибочно начала команд, и только когда будет известно, от какой позиции разбирать, станет понятно, какие разборы были правильными, а какие ошибочными. Никакой разницы. Это только всяким MIPS со всегда 4 байта на команду хорошо, но эта система нерасширяема.
Вот если бы применяли ещё подход в стиле utf-8, то там можно было бы с любой позиции начинать анализировать. Но такой архитектуры я ещё не видел.
Схема с длиной хороша тем, что гарантирует правильный разбор при наличии ещё неизвестных команд, и таки особенно это ценно для подпространства nop-if-unknown. Префиксы её не ломают, а усложнение по сравнению с тем, что нагородили в x86, не такое фатальное.
Поэтому, чтобы не усложнять ситуацию - лучше в тех случаях, когда обрабатывать не нужно - именно это и делать, оставляя все строкой и передавая эту строку дальше 'как есть'.
Если она соответствует канону представления - да. Иначе - нет. Передавая как есть непроверенный внешний ввод, вы получаете другую проблему - даёте его туда, где ожидают уже проверенные корректные данные, и может случиться реально что угодно, вплоть до тяжёлых проблем секьюрити.
Вот где-то мелькал пример, как выписали ребёнку свидетельство о рождении с датой 31 ноября, и пока он не пошёл в садик, никто не заметил проблемы. В компьютер ввести такое было нельзя. Или проще: 9/11/2001 это 9 ноября или 11 сентября 2001? Сейчас все грамотные наверняка знают, что второе, но количество странных представлений дат, включая культуры, где не dd-mm-yy или dd.mm.yy, а dd/mm/yy, зашкаливает способности автоматического опознания.
Поэтому разбор с проверкой на границе зоны ответственности за корректность данных - обязателен. А дальше - если переводится обратно в строку, а не в выделенный тип Date, и в таком виде бегает между компонентами - я не против, это уже вопрос внутренней политики.
И программист еще до написания кода должен иметь модель того, что он будет реализовывать. Иначе в принципе быть не может, потому что код это проекция вашей мысли на язык машины.
Вообще-то модель присутствует далеко не всегда, мягко говоря. Достаточно часто срабатывают и другие подходы: например, просто начать писать, втыкая метки TODO во все места, где можно и нельзя, потом расширяя, и уже по результату написания кода начиная понимать, где какие обобщения и абстракции вводить, что надо выносить в структуры, классы, где подставлять базовые классы, и всё такое. Я достаточно часто в таком режиме работаю и он меня не подводил, если я вообще в принципе представляю себе, как надо решать на глобальном уровне.
Модель в голове возможна только в самых простых и очевидных случаях. В остальных, как правило, проходит несколько PoC, которые пишутся так, что из них можно сделать что-то полезное, но можно и просто выбросить, если не подошли. И тот PoC, который показал хоть что-то полезное, идёт в развитие.
Не знаю, как у вас получается, что сначала есть полная мысль, а потом из неё порождается код. Может, в некоторых доменах такое и возможно. Но я с ними незнаком.
А вот для того, чтобы легко преобразовывать промежуточные состояния в следующие версии, и нужно соблюдение некоторых принципов. В какой-то мере это и обсуждаемое, но не как главное.
я наглядно показал на что это влияет
Я честно пытался найти в ваших репликах. Не нашёл.
Это принцип организации кода, т.е. что бы его применять у вас уже должно быть то, что вы будете организовывать.
О! А теперь вы играете за мою сторону? Пишем код. На каком-то этапе (чем раньше, тем лучше, но это как повезёт) осознаём, что тут лучше разделить на разные сущности и прописать взаимодействие между ними. И вот тут разделение происходит по одной из двух причин: 1) Неподъёмно-зашкальная сложность конструкта - что хочется разделить даже искусственно, потому что есть возможность сгруппировать. 2) Вместо одного фиксированного варианта из сторон взаимодействия - требуется подставлять в зависимости от неважно чего (но реальной потребности) две или больше. Это включает в себя и тестирование: стабы, моки, как бы их сегодня ни звали - и реальные применения, как в примере с разными типами принтеров.
Но, и снова, должен быть код и должно быть понимание, что его надо разделять. Ну или, по-вашему, кода ещё нет, но есть гарантированное на всех этапах представление, что там должно быть (в общем случае - не верю, но в частном - естественно, бывает).
Т.е. вы не понимаете, что такое S
Ну я, очевидно, понимаю его иначе, чем вы. Если вы от этого считаете, что я его не понимаю... извините, это не ко мне.
Например, все шаблоны проектирования которые вы используете проходят проверку на принципы SOLID.
Серьёзно? Так уж и все? Мощная телепатия, однако. Может, вы тогда назовёте хотя бы 5 (магическая цифра) "шаблонов проектирования", которые я использую?
Если я вас правильно понял, эти ответы уже должны содержаться в описании данного принципа.
Нет. Ответы в задаче. Но эти принципы позволяют чётче рассмотреть вопрос и сформулировать ответ, чем туманный SRP.
Тестов на них не напишешь, так как ветвлений логики слишком много, а каждое ветвление это умножение кол-ва тестов на 2.
А вы считаете качество тестов в покрытии всех веток? Местами это, конечно, имеет смысл, но делать из этого икону - поспешно.
Возможно, вам не приходилось работать с хорошо написанным кодом ((
Мне приходилось. И далеко не всегда, мягко говоря, его тестировали в режиме 100% покрытия веток (я уж не вспоминаю, что само по себе 100% покрытие недостаточно, проблема может быть в конкретной комбинации условий).
Красивый пример, но исходная проблема именно в том, что дату пытались обрабатывать как время. Если что-то записано в виде 2005-11-02, то читать его как 2005-11-02T00:00:00 было уже принципиальной ошибкой чтения. Да, это тоже вопрос правильной типизации. В базах данных, например, поэтому типы данных date, time и datetime попарно различны.
Это дублирование информации. Нет веских причин не включить число 100 куда-то внутрь определения Ruble , и отображение настроить соответственно.
Это зависит. Я работал с американскими биржевиками и у них часть операций определена в центах, а часть (типа комиссии за биржевую операцию) в 1/10000 цента. Это та же валюта, но дискрет таки другой.
Вы не привязывайтесь к языкам. Пусть это будет ваш лично Decimal
Ну вы назвали его именно Decimal, а не просто Money или что-то подобное. Это уже предполагало, IMHO, привязку. Потому я и попросил уточнений.
Вы не согласны с подходом создания типов для реализации доменной логики
Согласен и привёл уточнения к нему, при подтверждении общего подхода.
или вам просто сильно хотелось меня "макнуть" в пробелы в моих знаниях (о которых я и сам в курсе)?
Непонятно, зачем вы пытаетесь защищаться. По-моему, как раз оптимальный метод дискуссии, чтобы получить какой-то конструктивный результат, это попытаться расширить и углубить полученное от другого и на этом основании уже с чем-то соглашаться, чему-то возражать - но без своего взноса оно превращается в бессмысленную полемику. Вы же, наоборот, попытку внести конструктив и уточнение - восприняли в штыки... ?
Да, естественно, надо понимать, до каких пределов эта самая fixed point и в каком варианте работает, и что для этого нужно. Ваш пример очень простой, я предлагаю взять что-то вроде "взять 1.5% налога на малиновые штаны от суммы в копейках". При идеальной точности и округлении до копеек, от 33 копеек это будет ещё 0, от 34 - одна копейка. И это надо правильно вычислять, и тут вопрос, как именно это делать. Если мы, например, при двух цифрах после точки (запятой) умножим на 1.5 и округлим, получим 49.5 округлённое до 50. Разделив на 100 и снова округлив по стандартному _у нас_ для финансовых расчётов round-half-up, получим 1 копейку. Уже неверно, должно быть ещё 0. Привет, двойное округление и его последствия. И вот тут промежуточный результат, получается, должен быть ещё в честной плавучке и с запасом точности, а округление (например, через quantize, в этом модуле) - только финально. Это простейший случай, бывают и хитрее.
В доке по модулю умножение и деление упомянуто "в пику" сложению и вычитанию, при которых квант не меняется (по крайней мере пока не будет переполнение за пределы значащего при сложении). Это ещё одна загвоздка, ещё проще и банальнее, чем предыдущая. Пусть у нас 7 цифр:
оно печатает Decimal('1.000000E+7')... упс, потеряли цифру: 10000000 вместо правильного 10000003. Всё, ваш баланс не сошёлся.
С этим можно бороться, да. Или применить заведомо завышенное количество значащих цифр - а сколько их нужно будет на самом деле? Умолчание у этого модуля 28, это как раз по принципу "педаль в пол, чтобы не плакались даже с зимбабвийскими долларами, коих 2 триллиона на один американский". Но как определить, что и этого количества цифр перестало хватать?
Или включить Rounded trap: `decimal.getcontext().traps[decimal.Rounded] = True` - и получите честное питоновское исключение. На время таких операций он должен быть включен. На время, например, делений при вычислении тех же 1.5% - выключен, при этом имея гарантированный запас точности (проверив значения, что они не выползут за пределы). Включаем, выключаем... I like to move it, move it.
А теперь попробуем понять, какая доля тех, кто реализует эти операции на таком же Decimal, вообще хотя бы раз читала про подобные грабельки - не говоря о том, чтобы постоянно держать их в памяти на каждой операции.
Это должно было, как минимум, заметно упростить логику работы ОС.
Если ОС уже 64-битная, то разница есть только в загрузчике в не-EFI варианте. Если же и так грузилось через EFI, то ядро начинает работать уже в полностью выставленном режиме и разницы ему нет. Уже по драфту X86S делали правки в Linux, просто скостив легаси и оставив вариант, пригодный для обоих - там нет никакого особого кода для не-X86S.
но зато это тратило кучу ресурсов на сопровождение
Тут да, поддержка старых режимов это больше морока помнить их специфику и держать работающими при любых изменениях.
Про этот документ я хорошо в курсе, но данных там IMHO недостаточно, или я чего-то недопонимаю. В реализации для IEEE binary (можно смотреть легкопонятный и эффективный вариант, например, в berkeley-softfloat) там, где сдвиг вправо числа с меньшим порядком, используется так называемый jamming shift, который выполняет, по сути, округление до нечётного, в пределах дополнительных битов. В описании IBM ничего такого не сказано, и возникает вопрос на подумать.
Пусть у нас до сдвига второго слагаемого он заканчивается на 0x9123F сам по себе, и 0x9124F_0, если считать с той самой guard digit. Теперь за счёт разницы 2 между порядками надо сдвинуть вправо на 2 цифры. Что получится - 0x912_4 (где 4 это guard digit) или 0x912_5? Куда округлится за счёт этого F, вылетевшего за пределы даже guard digit?
Аналогичные процедуры для IEEE754, как уже сказал, округляют цифры до нечётного. Для HFP тут я бы ожидал корректировку вверх. Раз ничего не сказано, я бы предположил, что корректировки не происходит и реально выполняется как усечение к нулю, но есть таки сомнения. (Хм, перечитал версию для Z. Для BFP и DFP описано управление округлением. Для HFP ни слова и суть текста такая же как для 360... что, только усечение?)
И, далее, guard digit для чего именно используется? Я не вижу, чтобы описывалось округление на основании её значения (типа, >=0x8 - округляем вверх). Такое впечатление, что она нужна только для того, чтобы при вычитании, когда нормализованный порядок падает и значение надо сдвигать влево, она входила в сохраняемую часть.
По сути, от современной "плавучки" отличий два:
В том и дело, что для современной (подразумеваем IEEE754) сохранение данных для правильного округления, и дальше само округление, является критичным для корректности операций. Это и для BFP (IEEE754 binary), и для DFP (IEEE754 decimal - которую IBM зачем-то воплотила в железе).
а в издании 1968 г. защитная цифра применяется в обоих форматах.
Угу, сравнил версии 0 и 7 (декабрь 67; 68го у меня нет под рукой) - в декабре 67 уже сказано про "15 цифр, из которых одна guard". Спасибо, я не догадался посмотреть раньше. Всё равно с современной точки зрения это примитив... а вот исторически очень ценное свидетельство.
Абстракция сейчас - дешевле, чем рефакторинг потом!
И в подавляющем большинстве случаев, по моей практике, оказывается, что направление абстрагирования было выбрано неверно.
Зато где действуют по вашему принципу - проект переполнен архитектурной астронавтикой.
общеизвестный сборник ограничений SOLID
Из его общеизвестности не следует его приоритетность или даже банальная полезность.
Вся задача SOLID'а - сделать так, чтобы при последующей разработке не было мучительно больно от попыток добавить в проект новую фичу, не раз***в к хренам старые.
Только вот конкретный сборник из 5 правил к этой задаче имеет весьма отдалённое отношение.
A. Some operations like addition, subtraction, and multiplication by an integer will automatically preserve fixed point. Others operations, like division and non-integer multiplication, will change the number of decimal places and need to be followed-up with a quantize() step:
И ещё чуть ниже:
In developing fixed-point applications, it is convenient to define functions to handle the quantize() step:
>>> def mul(x, y, fp=TWOPLACES): return (x * y).quantize(fp)
То есть собственный режим это плавающая точка (определено только количество точных значащих цифр, но не квант точности), но фиксированную точность можно получить дополнительными операциями. Костыль предоставлен, пользуйтесь на здоровье.
Но с другой стороны, это позволяло сэкономить на длине команды: в System/360 1-байтовых команд не было, а в 8086 - были.
Может, в 16-битном режиме это было ещё полезно. В 32 уже сомнительно. В 64 однозначно нет. И сейчас почему-то слишком много однобайтовых кодов занято тем, что ещё в 32 битах надо было за редкостью загнать в 2-4 байта: навскидку по таблице: hlt, cmc, movs, cmps, pusha, popa, push seg, pop seg, lahf, sahf, stos, lods, scas, in, out, ins, outs, far ret, cli, sti, cld, std, stc... только тут уже 36 кодов. Или убрать вообще (xlat и для 8086 был избыточен; в 64 битах слишком мало убрали). А чтобы новое ввести, придумывают всякие EVEX2 префиксы (начала) на 4 байта.
Почему при смене разрядности не перекодировать всё, всё равно ведь старый декодер не смог бы исполнять код в другом режиме? Что Intel, что AMD думали чем угодно, но не головой. AMD простительно - они нищие были и это была отчаянная попытка выжить на минимуме ресурсов. Но Intel сами себе подгаживали чуть менее чем всегда.
Я взял как-то код одного полностью самописного (C++, без ASIO и прочих, на своём движке) прокси и сравнил объёмы кода под разные 64-битные архитектуры. ARM/64 с его тотальной 4-байтностью команд толще x86 на 1%. RISC-V толще процентов на 10 чем x86 без compressed (2-байтовых) команд, но тоньше на четверть при разрешении compressed. SystemZ раза в полтора толще x86, за счёт того, что 64-битные операции все загнаны в 6-байтовые команды - тут уже проблема совместимости, они её так решили.
попробуйте, хотя бы, определить длину команды -- с учётом всех этих идиотских префиксов
Префиксы не сильно мешают, если их сделать грамотно. Грамотно - это, например, так (конструирую наобум, для примера): представим себе, что команда состоит из нескольких чанков, все кроме последнего - префиксы. Каждый чанк, в установленном порядке бит, начинается с: 0 - 2 байта, 10 - 4 байта, 110 - 6 байт, и так далее (в принципе неограниченно). Дальше 4 бита: 0000...1101 - обычные команды, неизвестная команда вызывает исключение. 1110 - распределяется вендором (но длина задана раньше и мы можем на ней основываться). Если 1111 - дальше ещё два бита: 00 - префикс, неизвестный вызывает исключение; 01 - префикс, неизвестный игнорируется; 10 - главный чанк, неизвестное значение выполняется как NOP; 11 - ну, оставим в резерв для чего-то особого.
Это даёт однозначную расшифровку с учётом всего-всего (даже если не знаем, что это было) и возможность, в частности, добавлять команды, которые игнорируются младшими моделями. В истории уже несколько таких случаев: куча разных барьеров - последовательные процессоры без конвейера и OoO исполнения просто игнорируют; endbr для защиты от return-oriented hacking; инвалидация кэшей; префетч; хинты всех видов; возможно, ещё что-то забыл. Ну а простой вариант разбора длины команды даёт гарантию совместимого расширения и резкое упрощение декодера.
половину системных по своей сути команд сделали непривилегированными.
Там не половина, там сильно меньше - штук 7. Но да, и их достаточно, чтобы попортить жизнь.
Мотивация авторов x86 почти во всех решениях... мнэээ... сомнительна. И я пока не увидел, кто её такой задавал (конкретное имя) - не святой же дух приносил им эти решения...
Можно указания на конкретные утверждения в Principles of Operation?
Если всё так, как вы говорите, то из-за специфической терминологии IBM, которую я просто не опознаю. И потому прошу точные ссылки.
Ну так я образчик такого подхода и предлагал.
На самом деле не настолько. Его уже достаточно хорошо вылизали. Есть форумы, где вопрос "насколько неровность кодировки в x86 дороже ARM?" (ARM берётся, потому что много где, включая Apple) обжевали со всех сторон. Усреднённый вывод - всё это максимум пара процентов от суммарных затрат процессора. И это, да, даже с тем кошмаром, что в x86. Ну а если что-то поаккуратнее - так и с микроскопом не будет рассмотреть.
Если вы твёрдо знаете, что это "кошмарные" выливается в какие-то конкретные цифры, а не просто личные впечатления "ужас-ужас!" - поделитесь ссылкой. Мне будет крайне интересно.
Полная sequential consistency. В PoO ни слова про модель памяти в плане синхронизации между разными процессорами (ядрами). Барьерных команд нет, барьеры из какого-нибудь C просто компилируются в ноль команд. Значит, реального OoO нету - даже такого с TSO, как в x86.
Программисту удобно, да. Процессору - торможение.
По этому поводу уже высказался не один раз - нищие, которые поставили всё на один кон и выиграли, и при этом имели минимум ресурсов - обвинять их бесполезно. В конце концов, могло быть и хуже (вспоминаем IA64).
Ну цена в полтора раза по длине для пользователей SystemZ не страшна.
Меня в этом плане больше удручает модель OoO и его работы с памятью, вот тут потеря производительности может быть в разы. Но, вероятно, это тоже для данного сегмента рынка вполне приемлемо.
Ну так и в S/360 с потомками декодер по полусловам будет в большинстве случаев находить ошибочно начала команд, и только когда будет известно, от какой позиции разбирать, станет понятно, какие разборы были правильными, а какие ошибочными. Никакой разницы. Это только всяким MIPS со всегда 4 байта на команду хорошо, но эта система нерасширяема.
Вот если бы применяли ещё подход в стиле utf-8, то там можно было бы с любой позиции начинать анализировать. Но такой архитектуры я ещё не видел.
Схема с длиной хороша тем, что гарантирует правильный разбор при наличии ещё неизвестных команд, и таки особенно это ценно для подпространства nop-if-unknown. Префиксы её не ломают, а усложнение по сравнению с тем, что нагородили в x86, не такое фатальное.
Если она соответствует канону представления - да. Иначе - нет. Передавая как есть непроверенный внешний ввод, вы получаете другую проблему - даёте его туда, где ожидают уже проверенные корректные данные, и может случиться реально что угодно, вплоть до тяжёлых проблем секьюрити.
Вот где-то мелькал пример, как выписали ребёнку свидетельство о рождении с датой 31 ноября, и пока он не пошёл в садик, никто не заметил проблемы. В компьютер ввести такое было нельзя. Или проще: 9/11/2001 это 9 ноября или 11 сентября 2001? Сейчас все грамотные наверняка знают, что второе, но количество странных представлений дат, включая культуры, где не dd-mm-yy или dd.mm.yy, а dd/mm/yy, зашкаливает способности автоматического опознания.
Поэтому разбор с проверкой на границе зоны ответственности за корректность данных - обязателен. А дальше - если переводится обратно в строку, а не в выделенный тип Date, и в таком виде бегает между компонентами - я не против, это уже вопрос внутренней политики.
Вообще-то модель присутствует далеко не всегда, мягко говоря. Достаточно часто срабатывают и другие подходы: например, просто начать писать, втыкая метки TODO во все места, где можно и нельзя, потом расширяя, и уже по результату написания кода начиная понимать, где какие обобщения и абстракции вводить, что надо выносить в структуры, классы, где подставлять базовые классы, и всё такое. Я достаточно часто в таком режиме работаю и он меня не подводил, если я вообще в принципе представляю себе, как надо решать на глобальном уровне.
Модель в голове возможна только в самых простых и очевидных случаях. В остальных, как правило, проходит несколько PoC, которые пишутся так, что из них можно сделать что-то полезное, но можно и просто выбросить, если не подошли. И тот PoC, который показал хоть что-то полезное, идёт в развитие.
Не знаю, как у вас получается, что сначала есть полная мысль, а потом из неё порождается код. Может, в некоторых доменах такое и возможно. Но я с ними незнаком.
А вот для того, чтобы легко преобразовывать промежуточные состояния в следующие версии, и нужно соблюдение некоторых принципов. В какой-то мере это и обсуждаемое, но не как главное.
Я честно пытался найти в ваших репликах. Не нашёл.
О! А теперь вы играете за мою сторону? Пишем код. На каком-то этапе (чем раньше, тем лучше, но это как повезёт) осознаём, что тут лучше разделить на разные сущности и прописать взаимодействие между ними. И вот тут разделение происходит по одной из двух причин:
1) Неподъёмно-зашкальная сложность конструкта - что хочется разделить даже искусственно, потому что есть возможность сгруппировать.
2) Вместо одного фиксированного варианта из сторон взаимодействия - требуется подставлять в зависимости от неважно чего (но реальной потребности) две или больше. Это включает в себя и тестирование: стабы, моки, как бы их сегодня ни звали - и реальные применения, как в примере с разными типами принтеров.
Но, и снова, должен быть код и должно быть понимание, что его надо разделять. Ну или, по-вашему, кода ещё нет, но есть гарантированное на всех этапах представление, что там должно быть (в общем случае - не верю, но в частном - естественно, бывает).
Ну я, очевидно, понимаю его иначе, чем вы. Если вы от этого считаете, что я его не понимаю... извините, это не ко мне.
Серьёзно? Так уж и все? Мощная телепатия, однако. Может, вы тогда назовёте хотя бы 5 (магическая цифра) "шаблонов проектирования", которые я использую?
Нет. Ответы в задаче. Но эти принципы позволяют чётче рассмотреть вопрос и сформулировать ответ, чем туманный SRP.
А вы считаете качество тестов в покрытии всех веток? Местами это, конечно, имеет смысл, но делать из этого икону - поспешно.
Мне приходилось. И далеко не всегда, мягко говоря, его тестировали в режиме 100% покрытия веток (я уж не вспоминаю, что само по себе 100% покрытие недостаточно, проблема может быть в конкретной комбинации условий).
Красивый пример, но исходная проблема именно в том, что дату пытались обрабатывать как время. Если что-то записано в виде 2005-11-02, то читать его как 2005-11-02T00:00:00 было уже принципиальной ошибкой чтения. Да, это тоже вопрос правильной типизации. В базах данных, например, поэтому типы данных date, time и datetime попарно различны.
Это зависит. Я работал с американскими биржевиками и у них часть операций определена в центах, а часть (типа комиссии за биржевую операцию) в 1/10000 цента. Это та же валюта, но дискрет таки другой.
Ну вы назвали его именно Decimal, а не просто Money или что-то подобное. Это уже предполагало, IMHO, привязку. Потому я и попросил уточнений.
Согласен и привёл уточнения к нему, при подтверждении общего подхода.
Непонятно, зачем вы пытаетесь защищаться. По-моему, как раз оптимальный метод дискуссии, чтобы получить какой-то конструктивный результат, это попытаться расширить и углубить полученное от другого и на этом основании уже с чем-то соглашаться, чему-то возражать - но без своего взноса оно превращается в бессмысленную полемику. Вы же, наоборот, попытку внести конструктив и уточнение - восприняли в штыки... ?
Спасибо, понял. Тут вопросов больше нет.
Да, естественно, надо понимать, до каких пределов эта самая fixed point и в каком варианте работает, и что для этого нужно. Ваш пример очень простой, я предлагаю взять что-то вроде "взять 1.5% налога на малиновые штаны от суммы в копейках". При идеальной точности и округлении до копеек, от 33 копеек это будет ещё 0, от 34 - одна копейка. И это надо правильно вычислять, и тут вопрос, как именно это делать. Если мы, например, при двух цифрах после точки (запятой) умножим на 1.5 и округлим, получим 49.5 округлённое до 50. Разделив на 100 и снова округлив по стандартному _у нас_ для финансовых расчётов round-half-up, получим 1 копейку. Уже неверно, должно быть ещё 0. Привет, двойное округление и его последствия. И вот тут промежуточный результат, получается, должен быть ещё в честной плавучке и с запасом точности, а округление (например, через quantize, в этом модуле) - только финально. Это простейший случай, бывают и хитрее.
В доке по модулю умножение и деление упомянуто "в пику" сложению и вычитанию, при которых квант не меняется (по крайней мере пока не будет переполнение за пределы значащего при сложении). Это ещё одна загвоздка, ещё проще и банальнее, чем предыдущая. Пусть у нас 7 цифр:
оно печатает Decimal('1.000000E+7')... упс, потеряли цифру: 10000000 вместо правильного 10000003. Всё, ваш баланс не сошёлся.
С этим можно бороться, да. Или применить заведомо завышенное количество значащих цифр - а сколько их нужно будет на самом деле? Умолчание у этого модуля 28, это как раз по принципу "педаль в пол, чтобы не плакались даже с зимбабвийскими долларами, коих 2 триллиона на один американский". Но как определить, что и этого количества цифр перестало хватать?
Или включить Rounded trap: `decimal.getcontext().traps[decimal.Rounded] = True` - и получите честное питоновское исключение. На время таких операций он должен быть включен. На время, например, делений при вычислении тех же 1.5% - выключен, при этом имея гарантированный запас точности (проверив значения, что они не выползут за пределы). Включаем, выключаем... I like to move it, move it.
А теперь попробуем понять, какая доля тех, кто реализует эти операции на таком же Decimal, вообще хотя бы раз читала про подобные грабельки - не говоря о том, чтобы постоянно держать их в памяти на каждой операции.
Сложно...
Если ОС уже 64-битная, то разница есть только в загрузчике в не-EFI варианте. Если же и так грузилось через EFI, то ядро начинает работать уже в полностью выставленном режиме и разницы ему нет. Уже по драфту X86S делали правки в Linux, просто скостив легаси и оставив вариант, пригодный для обоих - там нет никакого особого кода для не-X86S.
Тут да, поддержка старых режимов это больше морока помнить их специфику и держать работающими при любых изменениях.
Про этот документ я хорошо в курсе, но данных там IMHO недостаточно, или я чего-то недопонимаю. В реализации для IEEE binary (можно смотреть легкопонятный и эффективный вариант, например, в berkeley-softfloat) там, где сдвиг вправо числа с меньшим порядком, используется так называемый jamming shift, который выполняет, по сути, округление до нечётного, в пределах дополнительных битов. В описании IBM ничего такого не сказано, и возникает вопрос на подумать.
Пусть у нас до сдвига второго слагаемого он заканчивается на 0x9123F сам по себе, и 0x9124F_0, если считать с той самой guard digit. Теперь за счёт разницы 2 между порядками надо сдвинуть вправо на 2 цифры. Что получится - 0x912_4 (где 4 это guard digit) или 0x912_5? Куда округлится за счёт этого F, вылетевшего за пределы даже guard digit?
Аналогичные процедуры для IEEE754, как уже сказал, округляют цифры до нечётного. Для HFP тут я бы ожидал корректировку вверх. Раз ничего не сказано, я бы предположил, что корректировки не происходит и реально выполняется как усечение к нулю, но есть таки сомнения. (Хм, перечитал версию для Z. Для BFP и DFP описано управление округлением. Для HFP ни слова и суть текста такая же как для 360... что, только усечение?)
И, далее, guard digit для чего именно используется? Я не вижу, чтобы описывалось округление на основании её значения (типа, >=0x8 - округляем вверх). Такое впечатление, что она нужна только для того, чтобы при вычитании, когда нормализованный порядок падает и значение надо сдвигать влево, она входила в сохраняемую часть.
В том и дело, что для современной (подразумеваем IEEE754) сохранение данных для правильного округления, и дальше само округление, является критичным для корректности операций. Это и для BFP (IEEE754 binary), и для DFP (IEEE754 decimal - которую IBM зачем-то воплотила в железе).
Угу, сравнил версии 0 и 7 (декабрь 67; 68го у меня нет под рукой) - в декабре 67 уже сказано про "15 цифр, из которых одна guard". Спасибо, я не догадался посмотреть раньше. Всё равно с современной точки зрения это примитив... а вот исторически очень ценное свидетельство.
То есть мы имеем что-то вроде раннего аналога Ethernet на два узла плюс недоописанная логика управления двумя компами, так? Очень мало данных;(
И в подавляющем большинстве случаев, по моей практике, оказывается, что направление абстрагирования было выбрано неверно.
Зато где действуют по вашему принципу - проект переполнен архитектурной астронавтикой.
Из его общеизвестности не следует его приоритетность или даже банальная полезность.
Только вот конкретный сборник из 5 правил к этой задаче имеет весьма отдалённое отношение.
Я видел и даже имел несчастье сопровождать объектную систему с виртуальными функциями на bash. При отсутствии в нём пользовательских типов.
Был бы тьюринг-полный язык, а место и для ООП, и для, простите, SOLID - найдётся.
Ну вот цитата оттуда же:
И ещё чуть ниже:
То есть собственный режим это плавающая точка (определено только количество точных значащих цифр, но не квант точности), но фиксированную точность можно получить дополнительными операциями. Костыль предоставлен, пользуйтесь на здоровье.
"Чистая" fixed point выполняла бы это сама.
Может, в 16-битном режиме это было ещё полезно. В 32 уже сомнительно. В 64 однозначно нет. И сейчас почему-то слишком много однобайтовых кодов занято тем, что ещё в 32 битах надо было за редкостью загнать в 2-4 байта: навскидку по таблице: hlt, cmc, movs, cmps, pusha, popa, push seg, pop seg, lahf, sahf, stos, lods, scas, in, out, ins, outs, far ret, cli, sti, cld, std, stc... только тут уже 36 кодов. Или убрать вообще (xlat и для 8086 был избыточен; в 64 битах слишком мало убрали). А чтобы новое ввести, придумывают всякие EVEX2 префиксы (начала) на 4 байта.
Почему при смене разрядности не перекодировать всё, всё равно ведь старый декодер не смог бы исполнять код в другом режиме? Что Intel, что AMD думали чем угодно, но не головой. AMD простительно - они нищие были и это была отчаянная попытка выжить на минимуме ресурсов. Но Intel сами себе подгаживали чуть менее чем всегда.
Я взял как-то код одного полностью самописного (C++, без ASIO и прочих, на своём движке) прокси и сравнил объёмы кода под разные 64-битные архитектуры. ARM/64 с его тотальной 4-байтностью команд толще x86 на 1%. RISC-V толще процентов на 10 чем x86 без compressed (2-байтовых) команд, но тоньше на четверть при разрешении compressed. SystemZ раза в полтора толще x86, за счёт того, что 64-битные операции все загнаны в 6-байтовые команды - тут уже проблема совместимости, они её так решили.
Префиксы не сильно мешают, если их сделать грамотно. Грамотно - это, например, так (конструирую наобум, для примера): представим себе, что команда состоит из нескольких чанков, все кроме последнего - префиксы. Каждый чанк, в установленном порядке бит, начинается с: 0 - 2 байта, 10 - 4 байта, 110 - 6 байт, и так далее (в принципе неограниченно). Дальше 4 бита: 0000...1101 - обычные команды, неизвестная команда вызывает исключение. 1110 - распределяется вендором (но длина задана раньше и мы можем на ней основываться). Если 1111 - дальше ещё два бита: 00 - префикс, неизвестный вызывает исключение; 01 - префикс, неизвестный игнорируется; 10 - главный чанк, неизвестное значение выполняется как NOP; 11 - ну, оставим в резерв для чего-то особого.
Это даёт однозначную расшифровку с учётом всего-всего (даже если не знаем, что это было) и возможность, в частности, добавлять команды, которые игнорируются младшими моделями. В истории уже несколько таких случаев: куча разных барьеров - последовательные процессоры без конвейера и OoO исполнения просто игнорируют; endbr для защиты от return-oriented hacking; инвалидация кэшей; префетч; хинты всех видов; возможно, ещё что-то забыл. Ну а простой вариант разбора длины команды даёт гарантию совместимого расширения и резкое упрощение декодера.
Там не половина, там сильно меньше - штук 7. Но да, и их достаточно, чтобы попортить жизнь.
Мотивация авторов x86 почти во всех решениях... мнэээ... сомнительна. И я пока не увидел, кто её такой задавал (конкретное имя) - не святой же дух приносил им эти решения...