Всякий, кому приходилось заниматься астрономическими расчетами, наверняка сталкивался с необходимостью переводить календарную дату в юлианскую и обратно. Для этого можной найти множество формул и алгоритмов, но все они имеют один существенный недостаток: ограниченную область дат. Как правило, они неприменимы для далекого прошлого - отрицательных юлианских дней. А необходимость забираться так далеко имеется. Например, численная эфемерида DE431 простирается в прошлое аж до 13200 г. до н.э.
Почему же имеющиеся алгоритмя врут в таких случаях? Исследование показывает, что главная причина связана с понятиями целочисленного частного и остатка. Дональд Кнут в своем фундаментальном труде "Искусство программирования" определял целочисленное частное чисел x и y как наибольшее целое, не превосходящее x/y. Иными словами, частное чисел 10 и 3 ожидаемо равно 3, но вот для чисел -10 и 3 результат должен быть -4, а вовсе не -3, потому что -4 - как раз наибольшее целое, не превосходящее -10/3=-3.333... Сообразно с этим, остаток определяется как неотрицательное число r, такое, что x=q·y+r, где q - определенное выше целочисленное частное.
Проблема в том, что популярные языки программирования этим определениям не следуют. Как правило, при вычислении частного дробная часть просто отбрасывается, и получается -10÷3=-3. Остаток тоже сплошь и рядом получается отрицательным. Из известных мне языков только Модула-2 реализует эти операции в том же смысле, как их понимает Кнут. Но стоит только корректно выразить эти операции, как отыскание календарных формул, годных для любых дат, становится простым.
Ниже приводится алгоритм вычисления юлианской даты по календарной и обратно, пригодный для любых дат. Формулы и их вывод можно найти здесь. Алгоритм написан на ныне мертвом, но очень популярном в прошлом языке Алгол-60. Для любителей живых даю две реализации: на языках Паскаль (ISO 7185) и Фортран. Для языка Паскаль нужно обратить внимание, что стандарт ISO 7185 определяет операцию mod точно в смысле Кнута, чего не скажешь про операцию div. Если ваш компилятор не следует стандарту и реализует mod иначе - выкручивайтесь самостоятельно. Любители всяких Сей и Яв, тоже пишите сами!
Вывод для тестового примера такой:
Почему же имеющиеся алгоритмя врут в таких случаях? Исследование показывает, что главная причина связана с понятиями целочисленного частного и остатка. Дональд Кнут в своем фундаментальном труде "Искусство программирования" определял целочисленное частное чисел x и y как наибольшее целое, не превосходящее x/y. Иными словами, частное чисел 10 и 3 ожидаемо равно 3, но вот для чисел -10 и 3 результат должен быть -4, а вовсе не -3, потому что -4 - как раз наибольшее целое, не превосходящее -10/3=-3.333... Сообразно с этим, остаток определяется как неотрицательное число r, такое, что x=q·y+r, где q - определенное выше целочисленное частное.
Проблема в том, что популярные языки программирования этим определениям не следуют. Как правило, при вычислении частного дробная часть просто отбрасывается, и получается -10÷3=-3. Остаток тоже сплошь и рядом получается отрицательным. Из известных мне языков только Модула-2 реализует эти операции в том же смысле, как их понимает Кнут. Но стоит только корректно выразить эти операции, как отыскание календарных формул, годных для любых дат, становится простым.
Ниже приводится алгоритм вычисления юлианской даты по календарной и обратно, пригодный для любых дат. Формулы и их вывод можно найти здесь. Алгоритм написан на ныне мертвом, но очень популярном в прошлом языке Алгол-60. Для любителей живых даю две реализации: на языках Паскаль (ISO 7185) и Фортран. Для языка Паскаль нужно обратить внимание, что стандарт ISO 7185 определяет операцию mod точно в смысле Кнута, чего не скажешь про операцию div. Если ваш компилятор не следует стандарту и реализует mod иначе - выкручивайтесь самостоятельно. Любители всяких Сей и Яв, тоже пишите сами!
Вывод для тестового примера такой:
2415020.000 1899 12 31 12 0 0.000000 2451545.000 2000 1 1 12 0 0.000000 -104998.829 -5000 7 12 16 6 32.870000 3547465.171 5000 7 12 16 6 32.869994( Алгоритм )
Tags: