advanced help
phrase:
attribute:
attribute:
attribute:
order:
per page:
clip:
action:
Results of 1 - 1 of about 725 for Android 12 (1.956 sec.)
android (2801), 12 (27802)
calfr.apl
#score: 5143
@author: Jean Forget
@digest: cc209dae970ae49fc62962f86a861ffb
@id: 10522
@mdate: 2016-02-03T14:33:16Z
@size: 178428
@type: text/html
author: Jean Forget
content-type: text/html; charset=UTF-8
copyright: © 2015, 2016 by Jean Forget
date: 2016-02-02
description: Converting Gregorian dates to French Revolutionary and vice-versa
#keywords: calfr (2394366), chkdata (544243), ← (440909), chkio (368843), chkdim (368843), ∆ (358325), expec (348263), nerr (341379), primidi (317475), vendemiaire (304794), ⍕⍴⍴ (281347), raisin (222586), ⍕⎕ (206663), ⍕⍴ (186158), ∇ (183867), gr2fr (174582), ∘.× (159198), fr2rd (157739), test1fr2rd (156363), test1gr2rd (156363), test1rd2fr (156363), test1gr2fr (156363), test1fr2gr (156363), ⍕ (149730), gr2rd (147869), prtfr (140503), calendrier (134933), testdata (123296), republicain (112953), ⎕ (109292), clobbered (102610), rata (98755)
#!/usr/bin/apl -f ⍝ index of Bits and Pieces ⍝ Explanations in English Explications en français . ⍝ Full text of the GPL License ∇ calfr∆license 'APL program to convert Gregorian dates' 'to French Revolutionary dates and the other way' '' 'Copyright (C) 2015, 2016 Jean Forget (JFORGET at cpan dot org)' '' 'Build date: 2016-02-02' '' 'Portability: L1 (tested with GNU-APL and NARS2000)' '' ' This program is distributed under the GNU Public License version 1 or later' '' ' You can find the text of the license in the LICENSE file or at' ' http://www.gnu.org/licenses/gpl-1.0.html.' '' ' Here is the summary of GPL:' '' ' This program is free software; you can redistribute it and/or modify' ' it under the terms of the GNU General Public License as published by' ' the Free Software Foundation; either version 1, or (at your option)' ' any later version.' '' ' This program is distributed in the hope that it will be useful,' ' but WITHOUT ANY WARRANTY; without even the implied warranty of' ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the' ' GNU General Public License for more details.' '' ' You should have received a copy of the GNU General Public License' ' along with this program; if not, write to the Free Software Foundation,' ' Inc., <http://www.fsf.org/>.' ∇ ⍝ Installing from GitHub (https://github.com/jforget/apl-calendar-french): ⍝ clone the Git repo and copy "workspaces/calfr.apl" to the "workspaces" sub-directory of your GNU-APL directory ⍝ or copy "workspaces/calfrnars.atf" to some place where NARS2000 will find it ⍝ Installing from browsing https://www.gnu.org/software/apl/Bits_and_Pieces/ ⍝ save the webpage as simple text into the "workspaces" sub-directory of your GNU-APL directory ∇ calfr∆usage 'Loading the module from the command line (for GNU-APL):' ' apl -f workspaces/calfr.apl' 'Loading the module from inside GNU-APL:' ' )LOAD calfr' 'Loading the module from inside NARS2000:' ' )IN calfrnars' 'Dates are vectors of 3 numbers YYYY MM DD. e.g.' ' DR ← 8 2 18 ⍝ for 18 Brumaire VIII' ' DG ← 1794 7 27 ⍝ for 27th July 1794' 'Gregorian to French Revolutionary:' ' DR ← calfr∆gr2fr DG' 'French Revolutionary to Gregorian:' ' DG ← calfr∆fr2gr DR' 'Pretty-printing:' ' STRING ← calfr∆prtfr DR' 'Pretty-printing today''s date:' ' STRING ← calfr∆prtfr calfr∆gr2fr 3↑⎕TS' ∇ ∇ R ← calfr∆year D R ← D +.× 1 0 0 ∇ ∇ R ← calfr∆month D R ← D +.× 0 1 0 ∇ ∇ R ← calfr∆day D R ← D +.× 0 0 1 ∇ ∇ R ← calfr∆zerojanvnd Y R ← Y ∘.× 1 0 0 R ← R + (⍴R) ⍴ 0 1 0 ∇ ∇ R ← calfr∆fr2rd DATE R ← 654019 + (calfr∆frbis calfr∆year DATE) + DATE +.× 365 30 1 ∇ ∇ R ← calfr∆frbis YEAR YEAR ← YEAR - 1 R ← - / ⌊ YEAR ∘.÷ 4 100 400 4000 R ← R + YEAR ∈ 3 7 11 15 ∇ ∇ R ← calfr∆gr2rd DATE; DIM DIM ← ⍴ DATE DATE←(DIM ⍴0 1 0) + DATE + (2≥calfr∆month DATE) ∘.× ¯1 12 0 R ← ¯428 + (-/ ⌊ (calfr∆year DATE) ∘.÷ 4 100 400) + ⌊DATE +.× 365 30.6 1 ∇ ∇ R ← calfr∆rd2fr N; ⎕IO; N1; YH; YL; YI; YR; DR; NR; CM; Y; M; D ⎕IO ← 1 N1 ← N - 654414 YH ← ⌈ N1 ÷ 365.24 YL ← ⌈ N1 ÷ 365.34 YI ← 0 , ⍳ ⌈/,YH-YL YR ← YL ∘.+ YI DR ← calfr∆zerojanvnd YR NR ← calfr∆fr2rd DR CM ← NR < N ∘.+ (⍴YI)⍴0 Y ← ⌈/YR×CM D ← N - ⌈/NR×CM M ← ⌈D÷30 D ← D - 30 × M - 1 R ← (Y ∘.× 1 0 0) + (M ∘.× 0 1 0) + D ∘.× 0 0 1 ∇ ∇ R ← calfr∆rd2gr N; ⎕IO; YH; YL; YI; YR; DR; NR; CM; Y; M; D; ML; MR ⎕IO ← 1 YH ← ⌈ N ÷ 365.24 YL ← ⌈ N ÷ 365.25 YI ← 0 , ⍳ ⌈/,YH-YL YR ← YL ∘.+ YI DR ← calfr∆zerojanvnd YR NR ← calfr∆gr2rd DR CM ← NR < N ∘.+ (⍴YI)⍴0 Y ← ⌈/YR×CM D ← N - ⌈/NR×CM ML ← ⌈D÷31 MR ← ML ∘.+ 0 1 DR ← (Y ∘.× 2 3 ⍴ 1 0 0) + (MR ∘.× 0 1 0) NR ← calfr∆gr2rd DR CM ← NR < N ∘.+ 0 0 M ← ⌈/MR×CM D ← N - ⌈/NR×CM R ← (Y ∘.× 1 0 0) + (M ∘.× 0 1 0) + D ∘.× 0 0 1 ∇ ∇ R ← calfr∆gr2fr D R ← calfr∆rd2fr calfr∆gr2rd D ∇ ∇ R ← calfr∆fr2gr D R ← calfr∆rd2gr calfr∆fr2rd D ∇ ∇ R ← calfr∆prtfr D; DAY; MONTH; CM; ⎕IO ⎕IO ← 1 DAY ← 10 8 ⍴ 'Décadi Primidi Duodi Tridi QuartidiQuintidiSextidi Septidi Octidi Nonidi ' R ← DAY[1 + 10 | calfr∆day D;] MONTH ← 13 11 ⍴ 'VendémiaireBrumaire Frimaire Nivôse Pluviôse Ventôse Germinal Floréal Prairial Messidor Thermidor Fructidor jour compl.' R ← R, ' ', (⍕ calfr∆day D), ' ', (MONTH[calfr∆month D;]), ' ', (calfr∆roman calfr∆year D), ', jour ', calfr∆feasts[¯30 + D +.× 0 30 1;] CM ← ' ' ≠ R R ← (CM ∨ 0,¯1↓CM) / R R ← (⌽∨\⌽R≠' ')/R ∇ ∇ R ← calfr∆roman N; NODES → ((N>0) ∧ N<4000)/CONV R ← ⍕ N → 0 CONV: NODES ← 40 4 ⍴ (calfr∆nodes 'IVX'), (calfr∆nodes 'XLC'), (calfr∆nodes 'CDM'), calfr∆nodes 'M??' R ← ,NODES[⎕IO + 30 20 10 0 + 10 10 10 10 ⊤ N;] R ← (R≠' ')/R ∇ ∇ R ← calfr∆nodes CH R ← (' ', CH) [ ' IVX' ⍳ ' I II III IV V VI VII VIIIIX ' ] ∇ ∇ R ← calfr∆feasts; V ⍝ include here the contents of feasts V ← '' ⍝ Vendémiaire V ← V, 'du Raisin ' V ← V, 'du Safran ' V ← V, 'de la Châtaigne ' V ← V, 'de la Colchique ' V ← V, 'du Cheval ' V ← V, 'de la Balsamine ' V ← V, 'de la Carotte ' V ← V, 'de l''Amarante ' V ← V, 'du Panais ' V ← V, 'de la Cuve ' V ← V, 'de la Pomme de terre ' V ← V, 'de l''Immortelle ' V ← V, 'du Potiron ' V ← V, 'du Réséda ' V ← V, 'de l''Âne ' V ← V, 'de la Belle de nuit ' V ← V, 'de la Citrouille ' V ← V, 'du Sarrasin ' V ← V, 'du Tournesol ' V ← V, 'du Pressoir ' V ← V, 'du Chanvre ' V ← V, 'de la Pêche ' V ← V, 'du Navet ' V ← V, 'de l''Amaryllis ' V ← V, 'du Bœuf ' V ← V, 'de l''Aubergine ' V ← V, 'du Piment ' V ← V, 'de la Tomate ' V ← V, 'de l''Orge ' V ← V, 'du Tonneau ' ⍝ Brumaire V ← V, 'de la Pomme ' V ← V, 'du Céleri ' V ← V, 'de la Poire ' V ← V, 'de la Betterave ' V ← V, 'de l''Oie ' V ← V, 'de l''Héliotrope ' V ← V, 'de la Figue ' V ← V, 'de la Scorsonère ' V ← V, 'de l''Alisier ' V ← V, 'de la Charrue ' V ← V, 'du Salsifis ' V ← V, 'de la Macre ' V ← V, 'du Topinambour ' V ← V, 'de l''Endive ' V ← V, 'du Dindon ' V ← V, 'du Chervis ' V ← V, 'du Cresson ' V ← V, 'de la Dentelaire ' V ← V, 'de la Grenade ' V ← V, 'de la Herse ' V ← V, 'de la Bacchante ' V ← V, 'de l''Azerole ' V ← V, 'de la Garance ' V ← V, 'de l''Orange ' V ← V, 'du Faisan ' V ← V, 'de la Pistache ' V ← V, 'du Macjon ' V ← V, 'du Coing ' V ← V, 'du Cormier ' V ← V, 'du Rouleau ' ⍝ Frimaire V ← V, 'de la Raiponce ' V ← V, 'du Turneps ' V ← V, 'de la Chicorée ' V ← V, 'de la Nèfle ' V ← V, 'du Cochon ' V ← V, 'de la Mâche ' V ← V, 'du Chou-fleur ' V ← V, 'du Miel ' V ← V, 'du Genièvre ' V ← V, 'de la Pioche ' V ← V, 'de la Cire ' V ← V, 'du Raifort ' V ← V, 'du Cèdre ' V ← V, 'du Sapin ' V ← V, 'du Chevreuil ' V ← V, 'de l''Ajonc ' V ← V, 'du Cyprès ' V ← V, 'du Lierre ' V ← V, 'de la Sabine ' V ← V, 'du Hoyau ' V ← V, 'de l''Érable-sucre ' V ← V, 'de la Bruyère ' V ← V, 'du Roseau ' V ← V, 'de l''Oseille ' V ← V, 'du Grillon ' V ← V, 'du Pignon ' V ← V, 'du Liège ' V ← V, 'de la Truffe ' V ← V, 'de l''Olive ' V ← V, 'de la Pelle ' ⍝ Nivôse V ← V, 'de la Tourbe ' V ← V, 'de la Houille ' V ← V, 'du Bitume ' V ← V, 'du Soufre ' V ← V, 'du Chien ' V ← V, 'de la Lave ' V ← V, 'de la Terre végétale ' V ← V, 'du Fumier ' V ← V, 'du Salpêtre ' V ← V, 'du Fléau ' V ← V, 'du Granit ' V ← V, 'de l''Argile ' V ← V, 'de l''Ardoise ' V ← V, 'du Grès ' V ← V, 'du Lapin ' V ← V, 'du Silex ' V ← V, 'de la Marne ' V ← V, 'de la Pierre à chaux ' V ← V, 'du Marbre ' V ← V, 'du Van ' V ← V, 'de la Pierre à plâtre' V ← V, 'du Sel ' V ← V, 'du Fer ' V ← V, 'du Cuivre ' V ← V, 'du Chat ' V ← V, 'de l''Étain ' V ← V, 'du Plomb ' V ← V, 'du Zinc ' V ← V, 'du Mercure ' V ← V, 'du Crible ' ⍝ Pluviôse V ← V, 'de la Lauréole ' V ← V, 'de la Mousse ' V ← V, 'du Fragon ' V ← V, 'du Perce-neige ' V ← V, 'du Taureau ' V ← V, 'du Laurier-thym ' V ← V, 'de l''Amadouvier ' V ← V, 'du Mézéréon ' V ← V, 'du Peuplier ' V ← V, 'de la Cognée ' V ← V, 'de l''Ellébore ' V ← V, 'du Brocoli ' V ← V, 'du Laurier ' V ← V, 'de l''Avelinier ' V ← V, 'de la Vache ' V ← V, 'du Buis ' V ← V, 'du Lichen ' V ← V, 'de l''If ' V ← V, 'de la Pulmonaire ' V ← V, 'de la Serpette ' V ← V, 'du Thlaspi ' V ← V, 'du Thymelé ' V ← V, 'du Chiendent ' V ← V, 'de la Traînasse ' V ← V, 'du Lièvre ' V ← V, 'de la Guède ' V ← V, 'du Noisetier ' V ← V, 'du Cyclamen ' V ← V, 'de la Chélidoine ' V ← V, 'du Traîneau ' ⍝ Ventôse V ← V, 'du Tussilage ' V ← V, 'du Cornouiller ' V ← V, 'du Violier ' V ← V, 'du Troène ' V ← V, 'du Bouc ' V ← V, 'de l''Asaret ' V ← V, 'de l''Alaterne ' V ← V, 'de la Violette ' V ← V, 'du Marsault ' V ← V, 'de la Bêche ' V ← V, 'du Narcisse ' V ← V, 'de l''Orme ' V ← V, 'de la Fumeterre ' V ← V, 'du Vélar ' V ← V, 'de la Chèvre ' V ← V, 'de l''Épinard ' V ← V, 'du Doronic ' V ← V, 'du Mouron ' V ← V, 'du Cerfeuil ' V ← V, 'du Cordeau ' V ← V, 'de la Mandragore ' V ← V, 'du Persil ' V ← V, 'du Cochléaria ' V ← V, 'de la Pâquerette ' V ← V, 'du Thon ' V ← V, 'du Pissenlit ' V ← V, 'de la Sylvie ' V ← V, 'du Capillaire ' V ← V, 'du Frêne ' V ← V, 'du Plantoir ' ⍝ Germinal V ← V, 'de la Primevère ' V ← V, 'du Platane ' V ← V, 'de l''Asperge ' V ← V, 'de la Tulipe ' V ← V, 'de la Poule ' V ← V, 'de la Blette ' V ← V, 'du Bouleau ' V ← V, 'de la Jonquille ' V ← V, 'de l''Aulne ' V ← V, 'du Couvoir ' V ← V, 'de la Pervenche ' V ← V, 'du Charme ' V ← V, 'de la Morille ' V ← V, 'du Hêtre ' V ← V, 'de l''Abeille ' V ← V, 'de la Laitue ' V ← V, 'du Mélèze ' V ← V, 'de la Ciguë ' V ← V, 'du Radis ' V ← V, 'de la Ruche ' V ← V, 'du Gainier ' V ← V, 'de la Romaine ' V ← V, 'du Marronnier ' V ← V, 'de la Roquette ' V ← V, 'du Pigeon ' V ← V, 'du Lilas ' V ← V, 'de l''Anémone ' V ← V, 'de la Pensée ' V ← V, 'de la Myrtille ' V ← V, 'du Greffoir ' ⍝ Floréal V ← V, 'de la Rose ' V ← V, 'du Chêne ' V ← V, 'de la Fougère ' V ← V, 'de l''Aubépine ' V ← V, 'du Rossignol ' V ← V, 'de l''Ancolie ' V ← V, 'du Muguet ' V ← V, 'du Champignon ' V ← V, 'de la Jacinthe ' V ← V, 'du Rateau ' V ← V, 'de la Rhubarbe ' V ← V, 'du Sainfoin ' V ← V, 'du Bâton-d''or ' V ← V, 'du Chamérisier ' V ← V, 'du Ver à soie ' V ← V, 'de la Consoude ' V ← V, 'de la Pimprenelle ' V ← V, 'de la Corbeille-d''or ' V ← V, 'de l''Arroche ' V ← V, 'du Sarcloir ' V ← V, 'du Statice ' V ← V, 'de la Fritillaire ' V ← V, 'de la Bourrache ' V ← V, 'de la Valériane ' V ← V, 'de la Carpe ' V ← V, 'du Fusain ' V ← V, 'de la Civette ' V ← V, 'de la Buglosse ' V ← V, 'du Sénevé ' V ← V, 'de la Houlette ' ⍝ Prairial V ← V, 'de la Luzerne ' V ← V, 'de l''Hémérocalle ' V ← V, 'du Trèfle ' V ← V, 'de l''Angélique ' V ← V, 'du Canard ' V ← V, 'de la Mélisse ' V ← V, 'du Fromental ' V ← V, 'du Martagon ' V ← V, 'du Serpolet ' V ← V, 'de la Faux ' V ← V, 'de la Fraise ' V ← V, 'de la Bétoine ' V ← V, 'du Pois ' V ← V, 'de l''Acacia ' V ← V, 'de la Caille ' V ← V, 'de l''Œillet ' V ← V, 'du Sureau ' V ← V, 'du Pavot ' V ← V, 'du Tilleul ' V ← V, 'de la Fourche ' V ← V, 'du Barbeau ' V ← V, 'de la Camomille ' V ← V, 'du Chèvrefeuille ' V ← V, 'du Caille-lait ' V ← V, 'de la Tanche ' V ← V, 'du Jasmin ' V ← V, 'de la Verveine ' V ← V, 'du Thym ' V ← V, 'de la Pivoine ' V ← V, 'du Chariot ' ⍝ Messidor V ← V, 'du Seigle ' V ← V, 'de l''Avoine ' V ← V, 'de l''Oignon ' V ← V, 'de la Véronique ' V ← V, 'du Mulet ' V ← V, 'du Romarin ' V ← V, 'du Concombre ' V ← V, 'de l''Échalotte ' V ← V, 'de l''Absinthe ' V ← V, 'de la Faucille ' V ← V, 'de la Coriandre ' V ← V, 'de l''Artichaut ' V ← V, 'de la Giroflée ' V ← V, 'de la Lavande ' V ← V, 'du Chamois ' V ← V, 'du Tabac ' V ← V, 'de la Groseille ' V ← V, 'de la Gesse ' V ← V, 'de la Cerise ' V ← V, 'du Parc ' V ← V, 'de la Menthe ' V ← V, 'du Cumin ' V ← V, 'du Haricot ' V ← V, 'de l''Orcanète ' V ← V, 'de la Pintade ' V ← V, 'de la Sauge ' V ← V, 'de l''Ail ' V ← V, 'de la Vesce ' V ← V, 'du Blé ' V ← V, 'de la Chalémie ' ⍝ Thermidor V ← V, 'de l''Épautre ' V ← V, 'du Bouillon-blanc ' V ← V, 'du Melon ' V ← V, 'de l''Ivraie ' V ← V, 'du Bélier ' V ← V, 'de la Prèle ' V ← V, 'de l''Armoise ' V ← V, 'du Carthame ' V ← V, 'de la Mûre ' V ← V, 'de l''Arrosoir ' V ← V, 'du Panis ' V ← V, 'du Salicor ' V ← V, 'de l''Abricot ' V ← V, 'du Basilic ' V ← V, 'de la Brebis ' V ← V, 'de la Guimauve ' V ← V, 'du Lin ' V ← V, 'de l''Amande ' V ← V, 'de la Gentiane ' V ← V, 'de l''Écluse ' V ← V, 'de la Carline ' V ← V, 'du Câprier ' V ← V, 'de la Lentille ' V ← V, 'de l''Aunée ' V ← V, 'de la Loutre ' V ← V, 'de la Myrte ' V ← V, 'du Colza ' V ← V, 'du Lupin ' V ← V, 'du Coton ' V ← V, 'du Moulin ' ⍝ Fructidor V ← V, 'de la Prune ' V ← V, 'du Millet ' V ← V, 'du Lycoperdon ' V ← V, 'de l''Escourgeon ' V ← V, 'du Saumon ' V ← V, 'de la Tubéreuse ' V ← V, 'du Sucrion ' V ← V, 'de l''Apocyn ' V ← V, 'de la Réglisse ' V ← V, 'de l''Échelle ' V ← V, 'de la Pastèque ' V ← V, 'du Fenouil ' V ← V, 'de l''Épine-vinette ' V ← V, 'de la Noix ' V ← V, 'de la Truite ' V ← V, 'du Citron ' V ← V, 'de la Cardère ' V ← V, 'du Nerprun ' V ← V, 'du Tagette ' V ← V, 'de la Hotte ' V ← V, 'de l''Églantier ' V ← V, 'de la Noisette ' V ← V, 'du Houblon ' V ← V, 'du Sorgho ' V ← V, 'de l''Écrevisse ' V ← V, 'de la Bagarade ' V ← V, 'de la Verge-d''or ' V ← V, 'du Maïs ' V ← V, 'du Marron ' V ← V, 'du Panier ' ⍝ jour complémentaire V ← V, 'de la Vertu ' V ← V, 'du Génie ' V ← V, 'du Travail ' V ← V, 'de l''Opinion ' V ← V, 'des Récompenses ' V ← V, 'de la Révolution ' R ← 366 21 ⍴ V ∇ ∇ R ← calfr∆testdata; V; L ⍝ include here the contents of testapl V ← ⍳0 V ← V, 1792 9 22 1 1 1 654415 V ← V, 1793 10 23 2 2 2 654811 V ← V, 1794 7 27 2 11 9 655088 V ← V, 1794 11 23 3 3 3 655207 V ← V, 1795 10 5 4 1 13 655523 V ← V, 1795 12 25 4 4 4 655604 V ← V, 1797 1 24 5 5 5 656000 V ← V, 1798 2 24 6 6 6 656396 V ← V, 1799 11 9 8 2 18 657019 V ← V, 1801 3 29 9 7 8 657524 V ← V, 1804 4 30 12 8 10 658652 V ← V, 1807 6 1 15 9 12 659779 V ← V, 1810 7 3 18 10 14 660907 V ← V, 1813 8 4 21 11 16 662035 V ← V, 1816 9 4 24 12 18 663162 V ← V, 2000 1 1 208 4 12 730120 V ← V, 2001 5 11 209 8 22 730616 V ← V, 1792 9 22 1 1 1 654415 V ← V, 1793 9 21 1 13 5 654779 V ← V, 1793 9 22 2 1 1 654780 V ← V, 1794 9 21 2 13 5 655144 V ← V, 1794 9 22 3 1 1 655145 V ← V, 1795 9 22 3 13 6 655510 V ← V, 1795 9 23 4 1 1 655511 V ← V, 1796 9 21 4 13 5 655875 V ← V, 1796 9 22 5 1 1 655876 V ← V, 1797 9 21 5 13 5 656240 V ← V, 1797 9 22 6 1 1 656241 V ← V, 1799 9 22 7 13 6 656971 V ← V, 1799 9 23 8 1 1 656972 V ← V, 1800 9 22 8 13 5 657336 V ← V, 1800 9 23 9 1 1 657337 V ← V, 1801 9 22 9 13 5 657701 V ← V, 1801 9 23 10 1 1 657702 V ← V, 1823 9 22 31 13 5 665736 V ← V, 1823 9 23 32 1 1 665737 V ← V, 1824 9 22 32 13 6 666102 V ← V, 1824 9 23 33 1 1 666103 V ← V, 1825 9 22 33 13 5 666467 V ← V, 1825 9 23 34 1 1 666468 V ← V, 1892 9 21 100 13 5 690938 V ← V, 1892 9 22 101 1 1 690939 V ← V, 1900 9 22 108 13 6 693860 V ← V, 1900 9 23 109 1 1 693861 V ← V, 1992 9 21 200 13 5 727462 V ← V, 1992 9 22 201 1 1 727463 V ← V, 2000 9 21 208 13 6 730384 V ← V, 2000 9 22 209 1 1 730385 V ← V, 2092 9 20 300 13 5 763986 V ← V, 2092 9 21 301 1 1 763987 V ← V, 2100 9 21 308 13 6 766908 V ← V, 2100 9 22 309 1 1 766909 V ← V, 2192 9 21 400 13 6 800511 V ← V, 2192 9 22 401 1 1 800512 V ← V, 2193 9 21 401 13 5 800876 V ← V, 2199 9 22 408 1 1 803068 V ← V, 2200 9 22 408 13 6 803433 V ← V, 2791 9 23 1000 1 1 1019292 V ← V, 2792 9 22 1001 1 1 1019657 V ← V, 3000 1 1 1208 4 12 1095363 V ← V, 3001 1 1 1209 4 11 1095728 V ← V, 3791 9 22 2000 1 1 1384534 V ← V, 3792 9 22 2001 1 1 1384900 V ← V, 4000 1 1 2208 4 12 1460605 V ← V, 4001 1 1 2209 4 12 1460971 V ← V, 4320 9 10 2528 12 24 1577735 V ← V, 4320 9 11 2528 12 25 1577736 V ← V, 4791 9 23 3000 1 1 1749777 V ← V, 4792 9 22 3001 1 1 1750142 V ← V, 5000 1 1 3208 4 12 1825848 V ← V, 5001 1 1 3209 4 11 1826213 V ← V, 5791 9 22 4000 1 1 2115019 V ← V, 5792 9 21 4001 1 1 2115384 V ← V, 6000 1 1 4208 4 13 2191090 V ← V, 6001 1 1 4209 4 13 2191456 V ← V, 6791 9 22 5000 1 1 2480261 V ← V, 6792 9 21 5001 1 1 2480626 V ← V, 7791 9 21 6000 1 1 2845503 V ← V, 7792 9 21 6001 1 1 2845869 L ← (⍴ V) ÷ 7 R ← (L, 7) ⍴ V ∇ ∇ R ← calfr∆teststring; V; L V ← '' ⍝ include here the contents of testapl1 V ← V, 'Primidi 1 Vendémiaire I, jour du Raisin ' V ← V, 'Duodi 2 Brumaire II, jour du Céleri ' V ← V, 'Nonidi 9 Thermidor II, jour de la Mûre ' V ← V, 'Tridi 3 Frimaire III, jour de la Chicorée ' V ← V, 'Tridi 13 Vendémiaire IV, jour du Potiron ' V ← V, 'Quartidi 4 Nivôse IV, jour du Soufre ' V ← V, 'Quintidi 5 Pluviôse V, jour du Taureau ' V ← V, 'Sextidi 6 Ventôse VI, jour de l''Asaret ' V ← V, 'Octidi 18 Brumaire VIII, jour de la Dentelaire ' V ← V, 'Octidi 8 Germinal IX, jour de la Jonquille ' V ← V, 'Décadi 10 Floréal XII, jour du Rateau ' V ← V, 'Duodi 12 Prairial XV, jour de la Bétoine ' V ← V, 'Quartidi 14 Messidor XVIII, jour de la Lavande ' V ← V, 'Sextidi 16 Thermidor XXI, jour de la Guimauve ' V ← V, 'Octidi 18 Fructidor XXIV, jour du Nerprun ' V ← V, 'Duodi 12 Nivôse CCVIII, jour de l''Argile ' V ← V, 'Duodi 22 Floréal CCIX, jour de la Fritillaire ' V ← V, 'Primidi 1 Vendémiaire I, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. I, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire II, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. II, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire III, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. III, jour de la Révolution ' V ← V, 'Primidi 1 Vendémiaire IV, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. IV, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire V, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. V, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire VI, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. VII, jour de la Révolution ' V ← V, 'Primidi 1 Vendémiaire VIII, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. VIII, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire IX, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. IX, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire X, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. XXXI, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire XXXII, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. XXXII, jour de la Révolution ' V ← V, 'Primidi 1 Vendémiaire XXXIII, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. XXXIII, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire XXXIV, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. C, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire CI, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. CVIII, jour de la Révolution ' V ← V, 'Primidi 1 Vendémiaire CIX, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. CC, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire CCI, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. CCVIII, jour de la Révolution ' V ← V, 'Primidi 1 Vendémiaire CCIX, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. CCC, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire CCCI, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. CCCVIII, jour de la Révolution' V ← V, 'Primidi 1 Vendémiaire CCCIX, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. CD, jour de la Révolution ' V ← V, 'Primidi 1 Vendémiaire CDI, jour du Raisin ' V ← V, 'Quintidi 5 jour compl. CDI, jour des Récompenses ' V ← V, 'Primidi 1 Vendémiaire CDVIII, jour du Raisin ' V ← V, 'Sextidi 6 jour compl. CDVIII, jour de la Révolution ' V ← V, 'Primidi 1 Vendémiaire M, jour du Raisin ' V ← V, 'Primidi 1 Vendémiaire MI, jour du Raisin ' V ← V, 'Duodi 12 Nivôse MCCVIII, jour de l''Argile ' V ← V, 'Primidi 11 Nivôse MCCIX, jour du Granit ' V ← V, 'Primidi 1 Vendémiaire MM, jour du Raisin ' V ← V, 'Primidi 1 Vendémiaire MMI, jour du Raisin ' V ← V, 'Duodi 12 Nivôse MMCCVIII, jour de l''Argile ' V ← V, 'Duodi 12 Nivôse MMCCIX, jour de l''Argile ' V ← V, 'Quartidi 24 Fructidor MMDXXVIII, jour du Sorgho ' V ← V, 'Quintidi 25 Fructidor MMDXXVIII, jour de l''Écrevisse' V ← V, 'Primidi 1 Vendémiaire MMM, jour du Raisin ' V ← V, 'Primidi 1 Vendémiaire MMMI, jour du Raisin ' V ← V, 'Duodi 12 Nivôse MMMCCVIII, jour de l''Argile ' V ← V, 'Primidi 11 Nivôse MMMCCIX, jour du Granit ' V ← V, 'Primidi 1 Vendémiaire 4000, jour du Raisin ' V ← V, 'Primidi 1 Vendémiaire 4001, jour du Raisin ' V ← V, 'Tridi 13 Nivôse 4208, jour de l''Ardoise ' V ← V, 'Tridi 13 Nivôse 4209, jour de l''Ardoise ' V ← V, 'Primidi 1 Vendémiaire 5000, jour du Raisin ' V ← V, 'Primidi 1 Vendémiaire 5001, jour du Raisin ' V ← V, 'Primidi 1 Vendémiaire 6000, jour du Raisin ' V ← V, 'Primidi 1 Vendémiaire 6001, jour du Raisin ' R ← 79 52 ⍴ V ∇ ∇ calfr∆alltests calfr∆testfr2rd calfr∆testgr2rd calfr∆testrd2fr calfr∆testrd2gr calfr∆testgr2fr calfr∆testfr2gr calfr∆testprtfr ∇ ∇ calfr∆testfr2rd; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata[;7] PARAM ← calfr∆testdata[;4 5 6] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0fr2rd 1 OK ←OK ∧ calfr∆test0fr2rd 2 OK ←OK ∧ calfr∆test1fr2rd 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1fr2rd 5 5 OK ←OK ∧ calfr∆test1fr2rd 5 3 3 OK ←OK ∧ calfr∆test1fr2rd 5 2 2 2 OK ←OK ∧ calfr∆test1fr2rd 7 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆fr2rd : no errors' ∇ ∇ R ← calfr∆test0fr2rd N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N] PAR ← PARAM[N;] LIB ← 'Checking calfr∆fr2rd with scalar date ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆fr2rd PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDATA ⍝ no need to check dimension, it is the empty vector LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ R ← calfr∆test1fr2rd DIM; LIB; EXP; GOT; NERR LIB ← 'Checking calfr∆fr2rd with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← DIM ⍴ EXPEC ⎕IO ← IO GOT ← calfr∆fr2rd (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ calfr∆testgr2rd; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata[;7] PARAM ← calfr∆testdata[;1 2 3] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0gr2rd 1 OK ←OK ∧ calfr∆test0gr2rd 2 OK ←OK ∧ calfr∆test1gr2rd 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1gr2rd 5 5 OK ←OK ∧ calfr∆test1gr2rd 5 3 3 OK ←OK ∧ calfr∆test1gr2rd 5 2 2 2 OK ←OK ∧ calfr∆test1gr2rd 7 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆gr2rd : no errors' ∇ ∇ R ← calfr∆test0gr2rd N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N] PAR ← PARAM[N;] LIB ← 'Checking calfr∆gr2rd with scalar date ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆gr2rd PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDATA ⍝ no need to check dimension, it is the empty vector LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ R ← calfr∆test1gr2rd DIM; LIB; EXP; GOT; NERR LIB ← 'Checking calfr∆gr2rd with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← DIM ⍴ EXPEC GOT ← calfr∆gr2rd (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ calfr∆testrd2fr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata[;4 5 6] PARAM ← calfr∆testdata[;7] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0rd2fr 1 OK ←OK ∧ calfr∆test0rd2fr 2 OK ←OK ∧ calfr∆test1rd2fr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1rd2fr 3 3 OK ←OK ∧ calfr∆test1rd2fr 15 3 OK ←OK ∧ calfr∆test1rd2fr 2 3 3 OK ←OK ∧ calfr∆test1rd2fr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆rd2fr : no errors' ∇ ∇ R ← calfr∆test0rd2fr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N] LIB ← 'Checking calfr∆rd2fr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆rd2fr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ R ← calfr∆test1rd2fr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆rd2fr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆rd2fr DIM ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ calfr∆testrd2gr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata[;1 2 3] PARAM ← calfr∆testdata[;7] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0rd2gr 1 OK ←OK ∧ calfr∆test0rd2gr 2 OK ←OK ∧ calfr∆test1rd2gr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1rd2gr 3 3 OK ←OK ∧ calfr∆test1rd2gr 15 3 OK ←OK ∧ calfr∆test1rd2gr 2 3 3 → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆rd2gr : no errors' ∇ ∇ R ← calfr∆test0rd2gr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N] LIB ← 'Checking calfr∆rd2gr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆rd2gr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ R ← calfr∆test1rd2gr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆rd2gr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆rd2gr DIM ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ calfr∆testgr2fr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata[;4 5 6] PARAM ← calfr∆testdata[;1 2 3] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0gr2fr 1 OK ←OK ∧ calfr∆test0gr2fr 2 OK ←OK ∧ calfr∆test1gr2fr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1gr2fr 3 3 OK ←OK ∧ calfr∆test1gr2fr 15 3 OK ←OK ∧ calfr∆test1gr2fr 2 3 3 OK ←OK ∧ calfr∆test1gr2fr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆gr2fr : no errors' ∇ ∇ R ← calfr∆test0gr2fr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N;] LIB ← 'Checking calfr∆gr2fr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆gr2fr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ R ← calfr∆test1gr2fr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆gr2fr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆gr2fr (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ calfr∆testfr2gr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata[;1 2 3] PARAM ← calfr∆testdata[;4 5 6] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0fr2gr 1 OK ←OK ∧ calfr∆test0fr2gr 2 OK ←OK ∧ calfr∆test1fr2gr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1fr2gr 3 3 OK ←OK ∧ calfr∆test1fr2gr 15 3 OK ←OK ∧ calfr∆test1fr2gr 2 3 3 OK ←OK ∧ calfr∆test1fr2gr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆fr2gr : no errors' ∇ ∇ R ← calfr∆test0fr2gr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N;] LIB ← 'Checking calfr∆fr2gr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆fr2gr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ R ← calfr∆test1fr2gr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking fr2gr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆fr2gr (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ ∇ calfr∆testprtfr; TD; TS; I; IMAX; PAR; EXP; GOT; N; IO; ⎕IO IO ← 2 LOOPIO: IO ← IO - 1 'Checking calfr∆prtfr with the full vector (a bit slow) and ⎕IO ', ⍕IO ⎕IO ← 1 TD ← calfr∆testdata[; 4 5 6 ] TS ← calfr∆teststring I ← 0 N ← 0 IMAX ← (⍴ TS)[1] LOOP: ⎕IO ← 1 I ← I + 1 → (I > IMAX)/END PAR ← TD[I;] EXP ← TS[I;] EXP ← (⌽∨\⌽EXP≠' ')/EXP ⎕IO ← IO GOT ← calfr∆prtfr PAR → ((⍴ EXP) = ⍴ GOT)/NEXT 'Different length: ', (⍕⍴ EXP), ' ', ⍕⍴GOT 'Expected: ', EXP 'Got : ', GOT N ← N + 1 → LOOP NEXT: → (∧/EXP=GOT)/LOOP 'Different content' 'Expected: ', EXP 'Got : ', GOT N ← N + 1 → LOOP END: 'Data errors with ⎕IO = ', (⍕IO), ' : ', ⍕N → IO / LOOPIO ∇ ]NEXTFILE English French Revolutionary Calendar calfr∆license Conversion between calendars Instructions for Use Installation Loading Basic use calfr∆usage Higher Orders Enclosed Values Implementation Date Elements calfr∆year calfr∆month calfr∆day calfr∆zerojanvnd - Concept of "zeroth day" calfr∆fr2rd - Converting from the French Revolutionary calendar to Rata Die calfr∆frbis - Number of leap years before year N (French Revolutionary calendar) calfr∆gr2rd - Converting from the Gregorian calendar to Rata Die calfr∆rd2fr - Converting from Rata Die to the French Revolutionary calendar calfr∆rd2gr - Converting from Rata Die to the Gregorian calendar The Conversion Functions calfr∆gr2fr - Conversion from the Gregorian calendar to the French Revolutionary calendar calfr∆fr2gr - Conversion from the French Revolutionary calendar to the Gregorian calendar Displaying the Dates calfr∆prtfr - Displaying a French Revolutionary calendar date calfr∆roman - Converting a number into Roman numerals calfr∆nodes - Building the nodes of Roman numerals calfr∆feasts - Feasts of the French Revolutionary calendar Built-in Tests calfr∆testdata - Test Data calfr∆teststring - Test alphanumeric data calfr∆alltests - Run all the tests calfr∆testfr2rd calfr∆test0fr2rd calfr∆test1fr2rd calfr∆testgr2rd calfr∆test0gr2rd calfr∆test1gr2rd calfr∆testrd2fr calfr∆test0rd2fr calfr∆test1rd2fr calfr∆testrd2gr calfr∆test0rd2gr calfr∆test1rd2gr calfr∆testgr2fr calfr∆test0gr2fr calfr∆test1gr2fr calfr∆testfr2gr calfr∆test0fr2gr calfr∆test1fr2gr calfr∆testprtfr See Also Software Internet Books French Revolutionary Calendar calfr∆license The text part of this repository is licensed under the terms of Creative Commons, with attribution and share-alike (CC-BY-SA). The code part of this repository is licensed with the GPL version 1.0 or later. As required by the GPL, each file with code must start with a one-line description of the program and the summary of the GPL. Here it is. ∇ calfr∆license 'APL program to convert Gregorian dates' 'to French Revolutionary dates and the other way' '' 'Copyright (C) 2015, 2016 Jean Forget (JFORGET at cpan dot org)' '' 'Build date:' '' 'Portability: L1 (tested with GNU-APL and NARS2000)' '' ' This program is distributed under the GNU Public License version 1 or later' '' ' You can find the text of the license in the LICENSE file or at' ' http://www.gnu.org/licenses/gpl-1.0.html.' '' ' Here is the summary of GPL:' '' ' This program is free software; you can redistribute it and/or modify' ' it under the terms of the GNU General Public License as published by' ' the Free Software Foundation; either version 1, or (at your option)' ' any later version.' '' ' This program is distributed in the hope that it will be useful,' ' but WITHOUT ANY WARRANTY; without even the implied warranty of' ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the' ' GNU General Public License for more details.' '' ' You should have received a copy of the GNU General Public License' ' along with this program; if not, write to the Free Software Foundation,' ' Inc., <http://www.fsf.org/>.' ∇ As you can see, this summary is executable code included in the software. So, after you have logged into APL and initialised your workspace with my script, you can display this summary at any moment. Portability: by converting the script file to ATF, the programs can be loaded into NARS2000. The only glitch is that any vowel with diacritic or any "c" with cedilla triggers a syntax error. So the build tool convert these characters to plain vowels and plain "c". After that, the ATF file gives programs that function correctly under NARS2000. Conversion between calendars This group of functions applies to three different calendars. The French Revolutionary calendar This calendar was in effect only in France and only from 1792 to 1805, but the programs allow you to use dates past this limit, until today and beyond. The dates are entered as vectors of 3 integer numbers YYYY MM DD. This calendar contains 12 months of 30 days each, plus 5 or 6 additional days. For convenience, these additional days are grouped together in what is considered as an additional month, numbered 13. The proleptic Gregorian calendar This is the Gregorian calendar, but extending in the past farther than 1582. Not only the leap year rule is the same as the Gregorian rule, but also the beginning of the year is always on January 1st, although it was not always the case during the Middle Ages with the actual calendar. The Gregorian dates are implemented as vectors of 3 numbers, in YYYY MM DD order. The Rata Die calendar This calendar ignores completely the notion of year. It counts only the days since January 1st, year 1, in the proleptic Gregorian calendar. Very convenient for computers, much less for humans. Actually, the script just uses the Rata Die calendar as a step between the two other calendars. You can still find some use with it, for example to compute how many days lie between two given dates. Instructions for Use Installation The calfr.apl file must be stored in the workspaces sub-directory of the current directory, so you can use the )LOAD APL command. You may store it in a wslib n sub-directory ( n from 1 to 9) and in this case, you will use the )LOAD n calfr.apl variant. Likewise, when the present text shows the command )LOAD , you can use the )XLOAD or )COPY variants instead. Installation for GNU-APL from GitHub : you may clone the repository and copy workspaces/calfr.apl to the workspaces subdirectory of your APL directory. Or else, display https://github.com/.../calfr.apl click on the "raw" button and save the file as "text only" into the workspaces of your APL directory. Installation for GNU-APL from GNU-APL Bits and Pieces : save the file as "text only" into the workspace subdirectory. Do not bother about all this English and French text, il will be hidden while loading the program into APL. Installation for NARS2000 from GitHub : Clone the repository and copy workspaces/calfrnars.atf to the c:\user\myself\Application Data\NARS2000\workspaces directory or, if you use GNU/Linux and Wine: /home/myself/.wine/drive_c/users/myself/Application Data/NARS2000/workspaces . Loading Loading into GNU-APL: you initialise an pristine workspace with the conversion functions with: apl -f workspaces/calfr.apl or with: apl )LOAD calfr Loading into NARS2000: you initialise an pristine workspace with the conversion functions with: )IN calfrnars Basic use You are now in the REPL loop of APL. You can for example ask to convert 13 Vendémiaire IV in this way: calfr∆fr2gr 4 1 13 1795 10 5 which means that 13 Vendémiaire IV is equivalent to 5th October 1795. In the other direction, converting 27th July 1794 is: calfr∆gr2fr 1794 7 27 2 11 9 which means 9 Thermidor II. To display the date in a more convenient way, use calfr∆prtfr in addition: calfr∆prtfr 2 11 9 Nonidi 9 Thermidor II, jour de la Mûre calfr∆prtfr calfr∆gr2fr 1794 7 27 Nonidi 9 Thermidor II, jour de la Mûre And to get the current day calfr∆prtfr calfr∆gr2fr 3↑⎕TS If you want to compute the number of days between two dates, use the Rata Die calendar. For example, if you want to know how many days elapsed from the uncle's coup (18 Brumaire VIII) and the nephew's coup (2nd December 1851), just type: (calfr∆gr2rd 1851 12 2) - calfr∆fr2rd 8 2 18 19015 calfr∆usage And here is the embedded help, callable from APL. ⍝ Installing from GitHub (https://github.com/jforget/apl-calendar-french): ⍝ clone the Git repo and copy "workspaces/calfr.apl" to the "workspaces" sub-directory of your GNU-APL directory ⍝ or copy "workspaces/calfrnars.atf" to some place where NARS2000 will find it ⍝ Installing from browsing https://www.gnu.org/software/apl/Bits_and_Pieces/ ⍝ save the webpage as simple text into the "workspaces" sub-directory of your GNU-APL directory ∇ calfr∆usage 'Loading the module from the command line (for GNU-APL):' ' apl -f workspaces/calfr.apl' 'Loading the module from inside GNU-APL:' ' )LOAD calfr' 'Loading the module from inside NARS2000:' ' )IN calfrnars' 'Dates are vectors of 3 numbers YYYY MM DD. e.g.' ' DR ← 8 2 18 ⍝ for 18 Brumaire VIII' ' DG ← 1794 7 27 ⍝ for 27th July 1794' 'Gregorian to French Revolutionary:' ' DR ← calfr∆gr2fr DG' 'French Revolutionary to Gregorian:' ' DG ← calfr∆fr2gr DR' 'Pretty-printing:' ' STRING ← calfr∆prtfr DR' 'Pretty-printing today''s date:' ' STRING ← calfr∆prtfr calfr∆gr2fr 3↑⎕TS' ∇ Higher Orders A date is implemented as a vector of 3 numbers. Several dates can be gathered into a date-vector, which will actually be an array of numbers. Thus, a 5-date vector will be an array with a 5 3 dimension. For example, the date vector: 21-JAN-1794 5-OCT-1795 9-NOV-1799 2-DEC-1851 31-MAR-2015 will be implemented by: DATEVEC 1794 1 21 1795 10 5 1799 11 9 1851 12 2 2015 3 31 ⍴ DATEVEC 5 3 Likewise, a 4 5 array of dates will be entered as a 4 5 3 block of numbers, and a 2 2 6 block of dates will be entered as a 2 2 6 3 block of numbers and so on. The calfr∆gr2fr and calfr∆fr2gr functions can deal with these structures, except when using a rank nearly equal to the maximum allowed value. For example, in this implementation APL is limited to rank 8, so the calfr∆gr2fr and calfr∆fr2gr functions are limited to rank 6. Continuing with the example above, converting the date vector is done with: calfr∆gr2fr DATEVEC 2 5 2 4 1 13 8 2 18 60 3 11 223 7 11 On the other hand, the calfr∆prtfr function is not compatible with date vectors or date arrays. It works only with scalar dates. Enclosed Values I know that APL allow to embed objects into others, using the ⊂ and ⊃ operators. But when I learnt APL more than thirty years ago, these operators did not exist. So, I have written the present script as a first version which does not use these operations. I had the intention of writing a second version which would rely on ⊂ et ⊃ . But I tried some experiments with the script as is . By using the ¨ (each) operator, the functions become compatible with enclosed objects. For example: V ← 2 2 ⍴ (1792 9 22) (1795 10 5) (1799 11 9), ⊂ 3↑⎕TS V 1792 9 22 1795 10 5 1799 11 9 2015 12 24 ⍴V 2 2 V1 ← calfr∆prtfr ¨ calfr∆gr2fr ¨ V V1 Primidi 1 Vendémiaire I, jour du Raisin Tridi 13 Vendémiaire IV, jour du Potiron Octidi 18 Brumaire VIII, jour de la Dentelaire Quartidi 4 Nivôse CCXXIV, jour du Soufre ⍴V1 2 2 Implementation Date Elements To extract the year from a date DATE , you juste have to write DATE[1] . To extract the day, just write DATE[3] . But this does not work with date vectors, for which you need to write DATEVEC[;1] and DATEVEC[;3] , which in turn does not work with date arrays, for which you write DATEARRAY[;;1] and DATEARRAY[;;3] . There are several ways to use the same functions for all. The simplest way is as follows: calfr∆year ∇ R ← calfr∆year D R ← D +.× 1 0 0 ∇ calfr∆month ∇ R ← calfr∆month D R ← D +.× 0 1 0 ∇ calfr∆day ∇ R ← calfr∆day D R ← D +.× 0 0 1 ∇ calfr∆zerojanvnd - Concept of "zeroth day" To help the description of the conversion algorithms, it is convenient to use the "zeroth day" of a given month. The zeroth day is a virtual day, before the first day of the month and after the last day of the previous month. For example, 0th March 2015 occurs before 1st March 2015 and after 28th February 2015. The fact that 0th March 2015 and 28th February 2015 share the same Rata Die is irrelevant, 0th March is after 28th February. Here is a function which builds a 0th January or a 0th Vendémiaire for a given year: ∇ R ← calfr∆zerojanvnd Y R ← Y ∘.× 1 0 0 R ← R + (⍴R) ⍴ 0 1 0 ∇ calfr∆fr2rd - Converting from the French Revolutionary calendar to Rata Die Let us start by computing the Rata Die for a given date in the French Revolutionary calendar. This number is the result of the addition of: 654414, which is the Rata Die for zeroth Vendémiaire I, (YYYY - 1) × 365, the number of days from zeroth Vendémiaire I to zeroth Vendémiaire of the target year, leaving aside the leap days, that is, the « 6 jour complémentaire », calfr∆frbis(YYYY), which gives the number of leap years before the target year, (MM - 1) × 30, the number of days from zeroth Vendémiaire until the zeroth day of the target month DD, to reach the target day. Actually, we reorder the terms to have a single additive constant, which gives the following terms: YYYY × 365, calfr∆frbis(YYYY), MM × 30, DD, additive constant. ∇ R ← calfr∆fr2rd DATE R ← 654019 + ( calfr∆frbis calfr∆year DATE) + DATE +.× 365 30 1 ∇ calfr∆frbis - Number of leap years before year N (French Revolutionary calendar) This subroutine gives the number of leap years preceding the current year. It allows refining the date computation, initialised with a computation using only 365-day years. Until year XX, the leap year rule is an astronomical rule, stating that the 1st Vendémiaire should happen on the autumn equinox. Then from year XX on, there would have been an arithmetical rule, similar to the Gregorian Calendar rule, introduced by Gilbert Romme's reform. The Romme rule states that a year is a leap year if it is a multiple of 4, except if it is a multiple of 100, but is nevertheless leap if it is a multiple of 400, except if it is a multiple of 4000. See below the comparison between both rules for the beginning of the Republican Era. The two "Arithmetic" columns simulate the hypothesis of applying the arithmetic rule from the beginning of the era. The "Astronomical" columns show the actual case, with the astronomical rule at first and the arithmetic rule after. The columns "Leap?" indicates leap years with an "X". The columns "frbis" show the number of leap years before the current year, which should be the result of the calfr∆frbis function. Arithmetic Astronomical Year Leap? frbis Leap? frbis 1 0 0 2 0 0 3 0 x 0 4 x 0 1 5 1 1 6 1 1 7 1 x 1 8 x 1 2 9 2 2 10 2 2 11 2 x 2 12 x 2 3 13 3 3 14 3 3 15 3 x 3 16 x 3 4 17 4 4 18 4 4 19 4 4 20 x 4 x 4 21 5 5 22 5 5 23 5 5 24 x 5 x 5 25 6 6 Actually, the two rules differ only for years IV, VIII, XII and XVI. So the subroutine applies the arithmetical rule starting from year I and then checks the year, tweaking the result is the year is one of the four exceptions. Remember that the subroutine begins with subtracting 1 from the year, therefore the values to check are 3, 7, 11 and 15. ∇ R ← calfr∆frbis YEAR YEAR ← YEAR - 1 R ← - / ⌊ YEAR ∘.÷ 4 100 400 4000 R ← R + YEAR ∈ 3 7 11 15 ∇ calfr∆gr2rd - Converting from the Gregorian calendar to Rata Die Although the leap year criteria for the French Revolutionary calendar are a bit complicated, converting from this calendar to Rata Die is simple when compared with the Gregorian Calendar. The filler period (additional days) is at the end of the year, so its shorter and variable duration has no impact on the computation. On the other hand, in the Gregorian calendar, the filler period is February, near the beginning of the year, so its influence spans over the main part of the year. In addition, the duration of the other months is variable: 30 or 31 days. This is why we use yet another calendar, the "shifted Gregorian calendar". In this calendar, the January and February months are assigned to the previous year so the year will begin on the First of March. In addition, for reasons shown below, the months are numbered from 4 (March) to 15 (February). So, 28th February 2015 becomes 2014 15 28 and 1st March 2015 becomes 2015 4 1 . In the table below, the left side show how to count the number of 31-day months before the current month and since the beginning of the shifted year. And the right side shows how to compute the number of days from 0th March to the zeroth day of the current month. M nb31 M 0.6 × M ¯2 + ⌊ 0.6 × M M ln nb 30.6 × M ¯122 + ⌊ 30.6 × M M 0 4 2.4 0 M 31 0 122.4 0 A 1 5 3.0 1 A 30 31 153.0 31 M 1 6 3.6 1 M 31 61 183.6 61 J 2 7 4.2 2 J 30 92 214.2 92 J 2 8 4.8 2 J 31 122 244.8 122 A 3 9 5.4 3 A 31 153 275.4 153 S 4 10 6.0 4 S 30 184 306.0 184 O 4 11 6.6 4 O 31 214 336.6 214 N 5 12 7.2 5 N 30 245 367.2 245 D 5 13 7.8 5 D 31 275 397.8 275 J 6 14 8.4 6 J 31 306 428.4 306 F 7 15 9.0 7 F 28? 29? 337 459.0 337 So here is the function: ∇ R ← calfr∆gr2rd DATE; DIM DIM ← ⍴ DATE DATE←(DIM ⍴0 1 0) + DATE + (2≥ calfr∆month DATE) ∘.× ¯1 12 0 R ← ¯428 + (-/ ⌊ ( calfr∆year DATE) ∘.÷ 4 100 400) + ⌊DATE +.× 365 30.6 1 ∇ calfr∆rd2fr - Converting from Rata Die to the French Revolutionary calendar Here is how it is done. Starting from the Rata Die value, the function computes a YL -to- YH interval of candidate years. Suppose we start with Rata Die value 672800 and that the candidate years are 50 to 53 inclusive. The program computes the full list of candidate years YR , that is, in this example, the vector 50 51 52 53 . Then the program turns this year vector into a date vector DR , consisting of the zeroth Vendémiaire for each year. DR 50 1 0 51 1 0 52 1 0 53 1 0 The calfr∆fr2rd function computes the Rata Die of these dates NR 672311 672676 673041 673407 and compares with the initial value 672800, which gives: CM 1 1 0 0 The proper year is the highest year for which the zeroth Vendémiaire has a Rata Die value less than the value given as a parameter. In the example above, this would give year 51. By subtracting the Rata Die of the zeroth Vendémiaire from the parameter, we get 124, which can easily yield "4 Pluviôse" ( 5 4 ) with simple divisions by 30. Remark: in the example above, the interval of candidate years has 4 values. Actually, in most cases there will be only one candidate year when the date is far from the year's beginning and end, and there will be two around the years' ends. Using 4 values instead of just 1 or 2 has a pedagogical purpose. Actually, the first date with a 3-value range occurs in year 3744 and the first 4-value range appears in year 7480. Other remark: when the input parameter is not a scalar, but a vector, array or higher ranked structure, the various variables also have a higher rank. The only question is what happens if a first Rata Die value yields a 1-value range for the candidate years and another one yields a 2-value range. In this case, the shorter range is extended to 2 values, so the YR variable will be properly rectangular. ∇ R ← calfr∆rd2fr N; ⎕IO; N1; YH; YL; YI; YR; DR; NR; CM; Y; M; D ⎕IO ← 1 N1 ← N - 654414 YH ← ⌈ N1 ÷ 365.24 YL ← ⌈ N1 ÷ 365.34 YI ← 0 , ⍳ ⌈/,YH-YL YR ← YL ∘.+ YI DR ← calfr∆zerojanvnd YR NR ← calfr∆fr2rd DR CM ← NR < N ∘.+ (⍴YI)⍴0 Y ← ⌈/YR×CM D ← N - ⌈/NR×CM M ← ⌈D÷30 D ← D - 30 × M - 1 R ← (Y ∘.× 1 0 0) + (M ∘.× 0 1 0) + D ∘.× 0 0 1 ∇ Summary of the local variables: YH year (high) YL year (low) YI year increments, to build the year range YR year range DR date range (0 Vendémiaire) NR number range ( Rata Die ) CM comparison Y year final value D day final value M month final value Here is an example using a vector, not a scalar, as the input parameter. Note that for the first value, the year range should include one year only, but because of the fourth value, this range was extended to three years. V←800505 800511 800879 2115019 calfr∆rd2fr V 400 12 30 400 13 6 402 1 3 4000 1 1 YH 400 401 402 4000 YL 400 400 401 3998 YI 0 1 2 YR 400 401 402 400 401 402 401 402 403 3998 3999 4000 DR 400 1 0 401 1 0 402 1 0 400 1 0 401 1 0 402 1 0 401 1 0 402 1 0 403 1 0 3998 1 0 3999 1 0 4000 1 0 NR 800145 800511 800876 800145 800511 800876 800511 800876 801241 2114288 2114653 2115018 CM 1 0 0 1 0 0 1 1 0 1 1 1 Y 400 400 402 4000 M 12 13 1 1 D 30 6 3 1 calfr∆rd2gr - Converting from Rata Die to the Gregorian calendar For this function, there are two options. The first consists in converting Rata Die to shifted Gregorian and then converting from shifted Gregorian to standard Gregorian. The second possibility consists in using twice the "possible value range", the first time to compute the year (as in calfr∆rd2fr ) and the second time to compute the month. I use this second way. Computing the upper and lower limits of the candidate month range involves a division by 29.5 and a division by 31. So, the 3-value range will arrive sooner than with the candidate years. It will arrive with a day number 620. Even if the guesstimate of the month is coarser than the estimated value of the year, we know that the computation will never involve more than 366 days or 12 months, so the range will have at most two values. Therefore, we do not bother refining the estimation and we always use a two-value range for the month, even if the guesstimate would give a single-value range. ∇ R ← calfr∆rd2gr N; ⎕IO; YH; YL; YI; YR; DR; NR; CM; Y; M; D; ML; MR ⎕IO ← 1 YH ← ⌈ N ÷ 365.24 YL ← ⌈ N ÷ 365.25 YI ← 0 , ⍳ ⌈/,YH-YL YR ← YL ∘.+ YI DR ← calfr∆zerojanvnd YR NR ← calfr∆gr2rd DR CM ← NR < N ∘.+ (⍴YI)⍴0 Y ← ⌈/YR×CM D ← N - ⌈/NR×CM ML ← ⌈D÷31 MR ← ML ∘.+ 0 1 DR ← (Y ∘.× 2 3 ⍴ 1 0 0) + (MR ∘.× 0 1 0) NR ← calfr∆gr2rd DR CM ← NR < N ∘.+ 0 0 M ← ⌈/MR×CM D ← N - ⌈/NR×CM R ← (Y ∘.× 1 0 0) + (M ∘.× 0 1 0) + D ∘.× 0 0 1 ∇ The Conversion Functions calfr∆gr2fr - Conversion from the Gregorian calendar to the French Revolutionary calendar After all theses complicated computations, the final conversion function is a bit of an anti-climax. ∇ R ← calfr∆gr2fr D R ← calfr∆rd2fr calfr∆gr2rd D ∇ calfr∆fr2gr - Conversion from the French Revolutionary calendar to the Gregorian calendar Same thing for the other conversion function. ∇ R ← calfr∆fr2gr D R ← calfr∆rd2gr calfr∆fr2rd D ∇ Displaying the Dates calfr∆prtfr - Displaying a French Revolutionary calendar date Gathering the various date elements: day name, day number, month name, etc, is simple enough. What is more difficult is that this gives a result with extraneous spaces and that we have to get rid of these spaces, while keeping the required spaces. ∇ R ← calfr∆prtfr D; DAY; MONTH; CM; ⎕IO ⎕IO ← 1 DAY ← 10 8 ⍴ 'Décadi Primidi Duodi Tridi QuartidiQuintidiSextidi Septidi Octidi Nonidi ' R ← DAY[1 + 10 | calfr∆day D;] MONTH ← 13 11 ⍴ 'VendémiaireBrumaire Frimaire Nivôse Pluviôse Ventôse Germinal Floréal Prairial Messidor Thermidor Fructidor jour compl.' R ← R, ' ', (⍕ calfr∆day D), ' ', (MONTH[ calfr∆month D;]), ' ', ( calfr∆roman calfr∆year D), ', jour ', calfr∆feasts [¯30 + D +.× 0 30 1;] CM ← ' ' ≠ R R ← (CM ∨ 0,¯1↓CM) / R R ← (⌽∨\⌽R≠' ')/R ∇ calfr∆roman - Converting a number into Roman numerals If the number is higher than 3999, it is displayed with indo-arab numerals. Same thing if zero or negative. ∇ R ← calfr∆roman N; NODES → ((N>0) ∧ N<4000)/CONV R ← ⍕ N → 0 CONV: NODES ← 40 4 ⍴ ( calfr∆nodes 'IVX'), ( calfr∆nodes 'XLC'), ( calfr∆nodes 'CDM'), calfr∆nodes 'M??' R ← ,NODES[⎕IO + 30 20 10 0 + 10 10 10 10 ⊤ N;] R ← (R≠' ')/R ∇ calfr∆nodes - Building the nodes of Roman numerals The word "nodes" comes from the French-written book Histoire comparée des numérations écrites (which would translate to "Compared History of Written Number Systems"), by Geneviève Guitel. The original french word is "nœuds". When dealing with radix b , a node is a number k × b n , with k between 0 and b - 1. This function provides a step to build a string which contains 10 substrings, each one being a radix-10 node, written with Roman numerals. Each node is filled with spaces to reach a common length of 4 chars. ∇ R ← calfr∆nodes CH R ← (' ', CH) [ ' IVX' ⍳ ' I II III IV V VI VII VIIIIX ' ] ∇ calfr∆feasts - Feasts of the French Revolutionary calendar This function lists all 366 feasts for all days in a French Revolutionary calendar year. ∇ R ← calfr∆feasts; V ⍝ include here the contents of feasts ∇ It returns an array of 366 lines of 21 chars, one line per day. 4 21↑calfr∆feasts du Raisin du Safran de la Châtaigne de la Colchique Built-in Tests calfr∆testdata - Test Data This function gives an array of n lines and 7 columns, holding the data to test the conversion functions. Each line contains the Gregorian date in YYYY MM DD format, then the French Revolutionary date in YYYY MM DD format and lastly the Rata Die value. For example 2 7↑calfr∆testdata 1792 9 22 1 1 1 654415 1793 10 23 2 2 2 654811 The first lines of the test data show that the 22nd September 1792 converts to 1st Vendémiaire I, with a Rata Die value of 654415. Likewise, the 23rd October 1793 converts to 2 Brumaire II, that is, Rata Die 654811. The values used in these built-in tests come from the Perl module DateTime::Calendar::FrenchRevolutionary . The program which turns these dates into an APL code chunk is available on GitHub . And a utility script (in Perl) in this project inserts the contents of testapl in the final script. ∇ R ← calfr∆testdata; V; L ⍝ include here the contents of testapl L ← (⍴ V) ÷ 7 R ← (L, 7) ⍴ V ∇ calfr∆teststring - Test alphanumeric data This function gives the expected calfr∆prtfr result for each corresponding line ot calfr∆testdata . For example 2 52↑calfr∆teststring Primidi 1 Vendémiaire I, jour du Raisin Duodi 2 Brumaire II, jour du Céleri The strings are produced and inserted into the final code in the same fashion as calfr∆testdata . ∇ R ← calfr∆teststring; V; L V ← '' ⍝ include here the contents of testapl1 ∇ calfr∆alltests - Run all the tests ∇ calfr∆alltests calfr∆testfr2rd calfr∆testgr2rd calfr∆testrd2fr calfr∆testrd2gr calfr∆testgr2fr calfr∆testfr2gr calfr∆testprtfr ∇ calfr∆testfr2rd This function checks calfr∆fr2rd with a wide set of parameters: two scalar dates, a date vector, a date array, and so on until a rank-7 structure of dates (that is, a rank-8 block of integers). Tests are run a first time with ⎕IO set to 1, a second time with ⎕IO set to 0. Each failed subtest prints an error message. If everything succeeds, the main test function prints a single message. ∇ calfr∆testfr2rd; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;7] PARAM ← calfr∆testdata [;4 5 6] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0fr2rd 1 OK ←OK ∧ calfr∆test0fr2rd 2 OK ←OK ∧ calfr∆test1fr2rd 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1fr2rd 5 5 OK ←OK ∧ calfr∆test1fr2rd 5 3 3 OK ←OK ∧ calfr∆test1fr2rd 5 2 2 2 OK ←OK ∧ calfr∆test1fr2rd 7 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆fr2rd : no errors' ∇ calfr∆test0fr2rd This function checks calfr∆fr2rd with a scalar date. ⎕IO is initialised with the global variable IO , actually a variable local to the upper function calfr∆testfr2rd and transmitted globally. The same transmission mechanism applies to PARAM (parameters for the checked function) and EXPEC (expected results). ∇ R ← calfr∆test0fr2rd N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N] PAR ← PARAM[N;] LIB ← 'Checking calfr∆fr2rd with scalar date ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆fr2rd PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDATA ⍝ no need to check dimension, it is the empty vector LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1fr2rd This function checks calfr∆fr2rd with a date vector or a higher rank structure. ⎕IO is initialised with the global variable IO , actually a variable local to the upper function calfr∆testfr2rd and transmitted globally. ∇ R ← calfr∆test1fr2rd DIM; LIB; EXP; GOT; NERR LIB ← 'Checking calfr∆fr2rd with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← DIM ⍴ EXPEC ⎕IO ← IO GOT ← calfr∆fr2rd (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testgr2rd ∇ calfr∆testgr2rd; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;7] PARAM ← calfr∆testdata [;1 2 3] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0gr2rd 1 OK ←OK ∧ calfr∆test0gr2rd 2 OK ←OK ∧ calfr∆test1gr2rd 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1gr2rd 5 5 OK ←OK ∧ calfr∆test1gr2rd 5 3 3 OK ←OK ∧ calfr∆test1gr2rd 5 2 2 2 OK ←OK ∧ calfr∆test1gr2rd 7 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆gr2rd : no errors' ∇ calfr∆test0gr2rd ∇ R ← calfr∆test0gr2rd N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N] PAR ← PARAM[N;] LIB ← 'Checking calfr∆gr2rd with scalar date ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆gr2rd PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDATA ⍝ no need to check dimension, it is the empty vector LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1gr2rd ∇ R ← calfr∆test1gr2rd DIM; LIB; EXP; GOT; NERR LIB ← 'Checking calfr∆gr2rd with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← DIM ⍴ EXPEC GOT ← calfr∆gr2rd (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testrd2fr ∇ calfr∆testrd2fr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;4 5 6] PARAM ← calfr∆testdata [;7] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0rd2fr 1 OK ←OK ∧ calfr∆test0rd2fr 2 OK ←OK ∧ calfr∆test1rd2fr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1rd2fr 3 3 OK ←OK ∧ calfr∆test1rd2fr 15 3 OK ←OK ∧ calfr∆test1rd2fr 2 3 3 OK ←OK ∧ calfr∆test1rd2fr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆rd2fr : no errors' ∇ calfr∆test0rd2fr ∇ R ← calfr∆test0rd2fr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N] LIB ← 'Checking calfr∆rd2fr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆rd2fr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1rd2fr ∇ R ← calfr∆test1rd2fr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆rd2fr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆rd2fr DIM ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testrd2gr ∇ calfr∆testrd2gr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;1 2 3] PARAM ← calfr∆testdata [;7] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0rd2gr 1 OK ←OK ∧ calfr∆test0rd2gr 2 OK ←OK ∧ calfr∆test1rd2gr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1rd2gr 3 3 OK ←OK ∧ calfr∆test1rd2gr 15 3 OK ←OK ∧ calfr∆test1rd2gr 2 3 3 → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆rd2gr : no errors' ∇ calfr∆test0rd2gr ∇ R ← calfr∆test0rd2gr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N] LIB ← 'Checking calfr∆rd2gr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆rd2gr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1rd2gr ∇ R ← calfr∆test1rd2gr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆rd2gr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆rd2gr DIM ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testgr2fr ∇ calfr∆testgr2fr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;4 5 6] PARAM ← calfr∆testdata [;1 2 3] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0gr2fr 1 OK ←OK ∧ calfr∆test0gr2fr 2 OK ←OK ∧ calfr∆test1gr2fr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1gr2fr 3 3 OK ←OK ∧ calfr∆test1gr2fr 15 3 OK ←OK ∧ calfr∆test1gr2fr 2 3 3 OK ←OK ∧ calfr∆test1gr2fr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆gr2fr : no errors' ∇ calfr∆test0gr2fr ∇ R ← calfr∆test0gr2fr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N;] LIB ← 'Checking calfr∆gr2fr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆gr2fr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1gr2fr ∇ R ← calfr∆test1gr2fr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆gr2fr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆gr2fr (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testfr2gr ∇ calfr∆testfr2gr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;1 2 3] PARAM ← calfr∆testdata [;4 5 6] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0fr2gr 1 OK ←OK ∧ calfr∆test0fr2gr 2 OK ←OK ∧ calfr∆test1fr2gr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1fr2gr 3 3 OK ←OK ∧ calfr∆test1fr2gr 15 3 OK ←OK ∧ calfr∆test1fr2gr 2 3 3 OK ←OK ∧ calfr∆test1fr2gr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆fr2gr : no errors' ∇ calfr∆test0fr2gr ∇ R ← calfr∆test0fr2gr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N;] LIB ← 'Checking calfr∆fr2gr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆fr2gr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1fr2gr ∇ R ← calfr∆test1fr2gr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking fr2gr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆fr2gr (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testprtfr ∇ calfr∆testprtfr; TD; TS; I; IMAX; PAR; EXP; GOT; N; IO; ⎕IO IO ← 2 LOOPIO: IO ← IO - 1 'Checking calfr∆prtfr with the full vector (a bit slow) and ⎕IO ', ⍕IO ⎕IO ← 1 TD ← calfr∆testdata [; 4 5 6 ] TS ← calfr∆teststring I ← 0 N ← 0 IMAX ← (⍴ TS)[1] LOOP: ⎕IO ← 1 I ← I + 1 → (I > IMAX)/END PAR ← TD[I;] EXP ← TS[I;] EXP ← (⌽∨\⌽EXP≠' ')/EXP ⎕IO ← IO GOT ← calfr∆prtfr PAR → ((⍴ EXP) = ⍴ GOT)/NEXT 'Different length: ', (⍕⍴ EXP), ' ', ⍕⍴GOT 'Expected: ', EXP 'Got : ', GOT N ← N + 1 → LOOP NEXT: → (∧/EXP=GOT)/LOOP 'Different content' 'Expected: ', EXP 'Got : ', GOT N ← N + 1 → LOOP END: 'Data errors with ⎕IO = ', (⍕IO), ' : ', ⍕N → IO / LOOPIO ∇ See Also Software In Perl: DateTime::Calendar::FrenchRevolutionary also available on GitHub . Also in Perl: Date::Convert::French_Rev , available on GitHub . Exists also in Ruby (not from me). Or else with Emacs using e-LISP (I did the superfluous, others did the backbone). Exists on Android (not from me either). Exists also on HP-48 and HP-50 ( GitHub repository ). Lastly, exists on HP-41 . Internet Of course, the Wikipedia entry . Claus Tondering's FAQ . The entry on the H2G2 website. A website in French. Books Quid 2001, M and D Frémy, publ. Robert Laffont, in French Agenda Républicain 197 (1988/89), publ. Syros Alternatives, in French, ISBN 2 86738 262-9 Any French schoolbook about the French Revolution The French Revolution, Thomas Carlyle, Oxford University Press, ISBN 0-19-281843-0, in English. Introduction à APL, S. Pommier, éditions Dunod, 1978, ISBN 2-04-010402-X, in French. Apprendre et appliquer le langage APL, B. Legrand, éditions Masson, 1981, ISBN 2-225-69421-4, in French. ]NEXTFILE Français Calendrier Républicain calfr∆license Conversion entre calendriers Mode d'emploi Installation Chargement Utilisation calfr∆usage Ordres supérieurs Utilisation de "enclose" Implémentation Éléments de date calfr∆year calfr∆month calfr∆day calfr∆zerojanvnd - Notion de « jour zéro » calfr∆fr2rd - Conversion du calendrier républicain vers Rata Die calfr∆frbis - Nombre d'années bissextiles avant l'année N (calendrier républicain) calfr∆gr2rd - Conversion du calendrier grégorien vers Rata Die calfr∆rd2fr - Conversion du Rata Die vers le calendrier républicain calfr∆rd2gr - Conversion du Rata Die vers le calendrier grégorien Les fonctions de conversion calfr∆gr2fr - Conversion du calendrier grégorien vers le calendrier républicain calfr∆fr2gr - Conversion du calendrier républicain vers le calendrier grégorien Affichage des dates calfr∆prtfr - Affichage d'une date du calendrier républicain calfr∆roman - Conversion d'un nombre en chiffres romains calfr∆nodes - Construction des nœuds de la numération romaine calfr∆feasts - Fêtes du calendrier républicain Tests internes calfr∆testdata - Données pour les tests calfr∆teststring - Données alphanumériques de tests calfr∆alltests - Lancement de tous les tests calfr∆testfr2rd calfr∆test0fr2rd calfr∆test1fr2rd calfr∆testgr2rd calfr∆test0gr2rd calfr∆test1gr2rd calfr∆testrd2fr calfr∆test0rd2fr calfr∆test1rd2fr calfr∆testrd2gr calfr∆test0rd2gr calfr∆test1rd2gr calfr∆testgr2fr calfr∆test0gr2fr calfr∆test1gr2fr calfr∆testfr2gr calfr∆test0fr2gr calfr∆test1fr2gr calfr∆testprtfr Voir également Logiciels Internet Livres Calendrier Républicain calfr∆license La partie texte de ce dépôt git est distribuée sous la licence Creative Commons avec attribution et partage dans les mêmes conditions (CC-BY-SA). La partie code de ce dépôt est distribuée sous la licence GPL version 1.0 ou ultérieure. Ainsi que le requiert la licence GPL, tout fichier de code doit commencer par un commentaire décrivant de façon sommaire le logiciel et résumant la GPL. La description sommaire en français : « Les fonctions de ce script permettent de faire des conversions du calendrier grégorien vers le calendrier républicain et vice-versa. » Quant au résumé de la GPL, le voici, en anglais (je ne suis pas assez calé pour traduire en français un texte de teneur juridique). ∇ calfr∆license 'APL program to convert Gregorian dates' 'to French Revolutionary dates and the other way' '' 'Copyright (C) 2015, 2016 Jean Forget (JFORGET at cpan dot org)' '' 'Build date:' '' 'Portability: L1 (tested with GNU-APL and NARS2000)' '' ' This program is distributed under the GNU Public License version 1 or later' '' ' You can find the text of the license in the LICENSE file or at' ' http://www.gnu.org/licenses/gpl-1.0.html.' '' ' Here is the summary of GPL:' '' ' This program is free software; you can redistribute it and/or modify' ' it under the terms of the GNU General Public License as published by' ' the Free Software Foundation; either version 1, or (at your option)' ' any later version.' '' ' This program is distributed in the hope that it will be useful,' ' but WITHOUT ANY WARRANTY; without even the implied warranty of' ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the' ' GNU General Public License for more details.' '' ' You should have received a copy of the GNU General Public License' ' along with this program; if not, write to the Free Software Foundation,' ' Inc., <http://www.fsf.org/>.' ∇ Comme vous pouvez le deviner, ce résumé fait partie intégrante du logiciel. Donc, une fois que vous êtes entrés sous APL et que vous avez initialisé votre espace de travail avec mon script, vous pouvez à tout moment afficher ce résumé. Portabilité : en convertissant le fichier script en fichier ATF, on peut charger les fonctions sous NARS2000. Juste un hic, les lettres accentuées et c-cédille déclenchent une erreur de syntaxe. La chaîne de compilation remplace donc ces lettres par des lettres inoffensives, voyelles sans accent et « c » sans cédille. Avec cette précaution, les programmes fonctionnent parfaitement sous NARS2000. Conversion entre calendriers Cette série de fonctions s'applique à trois calendriers différents. Le calendrier républicain Le calendrier républicain a été en vigueur en France de 1792 à 1805, mais les fonctions de ce script permettent d'utiliser des dates jusqu'à aujourd'hui et au-delà. Les dates sont représentées par un vecteur de trois nombres au format AAAA MM JJ. Il y a douze mois de 30 jours chacun, plus 5 ou 6 jours complémentaires à la fin de l'année. Pour des raisons de simplicité, ces jours complémentaires constituent un mois supplémentaire numéroté 13. Le calendrier grégorien proleptique Il s'agit du calendrier grégorien, extrapolé dans le passé au-delà de l'année 1582. Non seulement la règle des années bissextiles est celle du calendrier grégorien, mais en plus on considère que l'année commence toujours le premier janvier, ce qui n'était pas toujours le cas avec les calendriers réellement en usage au Moyen-Âge. Les dates grégoriennes sont exprimées sous la forme d'un vecteur de trois nombres, au format AAAA MM JJ. Le Rata Die (RD) C'est un calendrier qui ignore totalement les années. Il ne compte que les jours, à partir du 1 er janvier de l'an 1 du calendrier grégorien proleptique. Très pratique pour les programmes, beaucoup moins pour les humains. En fait, le calendrier Rata Die ne vous servira pas en tant que tel, c'est simplement un intermédiaire entre les deux autres. Vous pouvez en avoir besoin quand même par exemple pour calculer le nombre de jours entre deux dates. Mode d'emploi Installation Le fichier calfr.apl doit se trouver dans le sous-répertoire workspaces , pour compatibilité avec la commande )LOAD . Vous pouvez stocker ce fichier dans un sous-répertoire wslib n ( n valant de 1 à 9), auquel cas vous devrez utiliser la variante )LOAD n calfr.apl . De même, là où le mode d'emploi indique la commande )LOAD , vous pouvez utiliser les variantes )XLOAD ou )COPY . Installation pour GNU-APL à partir de GitHub : vous pouvez cloner le dépôt et copier workspaces/calfr.apl vers le sous-répertoire workspaces de votre répertoire APL. Ou alors, affichez https://github.com/.../calfr.apl en mode raw et sauvegardez-le en mode « texte seul » dans le sous-répertoire workspaces de votre répertoire APL. Installation pour GNU-APL à partir de GNU-APL Bits and Pieces : sauvegardez le fichier affiché en mode « texte seul » dans le sous-répertoire workspace . Ne vous préoccupez pas de tout le texte en anglais et en français, il sera masqué lors du chargement sous APL. Installation pour NARS2000 à partir de GitHub : clonez le dépôt et copier workspaces/calfrnars.atf vers le répertoire c:\user\moi-meme\Application Data\NARS2000\workspaces ou, si vous utilisez GNU/Linux et Wine : /home/moi-meme/.wine/drive_c/users/moi-meme/Application Data/NARS2000/workspaces . Chargement Chargement dans GNU-APL : vous chargez un espace de travail initialisé avec les fonctions de conversion par&nbsp: apl -f workspaces/calfr.apl ou bien avec : apl )LOAD calfr Chargement dans NARS2000 : vous chargez un espace de travail initialisé avec les fonctions de conversion par&nbsp: )IN calfrnars Utilisation Vous vous retrouvez alors dans la boucle REPL (lecture, évaluation, impression et boucle) d'APL. Vous pouvez alors demander la conversion du 13 Vendémiaire IV ainsi : calfr∆fr2gr 4 1 13 1795 10 5 ce qui veut dire que le 13 Vendémiaire IV correspond au 5 octobre 1795. Dans l'autre sens, la conversion du 27 juillet 1794 se fait ainsi : calfr∆gr2fr 1794 7 27 2 11 9 ce qui signifie 9 Thermidor II. Pour avoir la date sous forme plus agréable, utilisez calfr∆prtfr : calfr∆prtfr 2 11 9 Nonidi 9 Thermidor II, jour de la Mûre calfr∆prtfr calfr∆gr2fr 1794 7 27 Nonidi 9 Thermidor II, jour de la Mûre Et pour avoir la date du jour calfr∆prtfr calfr∆gr2fr 3↑⎕TS Si vous voulez calculer le nombre de jours entre deux dates, utilisez le Rata Die . Par exemple, vous voulez savoir combien de jours séparent le coup d'état du neveu (2 décembre 1851) du coup d'état de l'oncle (18 Brumaire VIII). Il suffit de taper : (calfr∆gr2rd 1851 12 2) - calfr∆fr2rd 8 2 18 19015 calfr∆usage Voici l'aide en ligne en anglais. ⍝ Installing from GitHub (https://github.com/jforget/apl-calendar-french): ⍝ clone the Git repo and copy "workspaces/calfr.apl" to the "workspaces" sub-directory of your GNU-APL directory ⍝ or copy "workspaces/calfrnars.atf" to some place where NARS2000 will find it ⍝ Installing from browsing https://www.gnu.org/software/apl/Bits_and_Pieces/ ⍝ save the webpage as simple text into the "workspaces" sub-directory of your GNU-APL directory ∇ calfr∆usage 'Loading the module from the command line (for GNU-APL):' ' apl -f workspaces/calfr.apl' 'Loading the module from inside GNU-APL:' ' )LOAD calfr' 'Loading the module from inside NARS2000:' ' )IN calfrnars' 'Dates are vectors of 3 numbers YYYY MM DD. e.g.' ' DR ← 8 2 18 ⍝ for 18 Brumaire VIII' ' DG ← 1794 7 27 ⍝ for 27th July 1794' 'Gregorian to French Revolutionary:' ' DR ← calfr∆gr2fr DG' 'French Revolutionary to Gregorian:' ' DG ← calfr∆fr2gr DR' 'Pretty-printing:' ' STRING ← calfr∆prtfr DR' 'Pretty-printing today''s date:' ' STRING ← calfr∆prtfr calfr∆gr2fr 3↑⎕TS' ∇ Ordres supérieurs Une date est représentée par un vecteur de 3 nombres. On peut organiser les dates en un vecteur de dates, qui sera en réalité un tableau de nombres. Ainsi, un vecteur de 5 dates sera un tableau de dimension 5 3 . Par exemple, le vecteur de dates : 21-JAN-1794 5-OCT-1795 9-NOV-1799 2-DEC-1851 31-MAR-2015 sera représenté par : DATEVEC 1794 1 21 1795 10 5 1799 11 9 1851 12 2 2015 3 31 ⍴ DATEVEC 5 3 De la même manière, un tableau 4 5 de dates sera représenté par un bloc 4 5 3 de nombres, un bloc 2 2 6 de dates sera représenté par un bloc 2 2 6 3 de nombres, et ainsi de suite. Les fonctions calfr∆gr2fr et calfr∆fr2gr sont compatibles avec toutes ces structures, sauf lorsque l'on arrive au voisinage du rang maximal. Par exemple, sur cette implémentation d'APL le rang maximal est 8, donc les fonctions commencent à provoquer des erreurs avec une structure de rang 7. Ainsi, la conversion du vecteur ci-dessus se fait par : calfr∆gr2fr DATEVEC 2 5 2 4 1 13 8 2 18 60 3 11 223 7 11 Par contre, la fonction calfr∆prtfr n'est pas compatible avec les vecteurs de dates ou les tableaux de dates. Elle accepte seulement les dates scalaires. Utilisation de "enclose" Je sais que APL permet d'inclure des objets dans d'autres, avec les opérateurs ⊂ et ⊃ . Mais cela n'existait pas lorsque j'ai appris APL il y a plus de trente ans. J'ai donc écrit le présent script sans chercher à utiliser ces opérateurs. J'avais l'intention d'écrire dans un deuxième temps un nouveau script qui reposerait sur ⊂ et ⊃ . Mais j'ai fait quelques expériences avec le script dans l'état actuel. En utilisant la fonction ¨ ( each ), les fonctions deviennent compatibles avec les objets « enclosed ». Exemple : V ← 2 2 ⍴ (1792 9 22) (1795 10 5) (1799 11 9), ⊂ 3↑⎕TS V 1792 9 22 1795 10 5 1799 11 9 2015 12 24 ⍴V 2 2 V1 ← calfr∆prtfr ¨ calfr∆gr2fr ¨ V V1 Primidi 1 Vendémiaire I, jour du Raisin Tridi 13 Vendémiaire IV, jour du Potiron Octidi 18 Brumaire VIII, jour de la Dentelaire Quartidi 4 Nivôse CCXXIV, jour du Soufre ⍴V1 2 2 Implémentation Éléments de date Pour extraire l'année d'une date DATE , il suffit d'écrire DATE[1] . Pour en extraire le jour, il suffit d'écrire DATE[3] . Mais cela ne fonctionne pas avec les vecteurs de dates pour lesquels il faut écrire DATEVEC[;1] et DATEVEC[;3] , ni avec les tableaux de dates pour lesquel il faut écrire DATEARRAY[;;1] et DATEARRAY[;;3] . Il y a plusieurs façons de s'en tirer et d'avoir une fonction compatible avec tous les rangs et toutes les dimensions. La plus simple consiste à écrire : calfr∆year ∇ R ← calfr∆year D R ← D +.× 1 0 0 ∇ calfr∆month ∇ R ← calfr∆month D R ← D +.× 0 1 0 ∇ calfr∆day ∇ R ← calfr∆day D R ← D +.× 0 0 1 ∇ calfr∆zerojanvnd - Notion de « jour zéro » Pour comprendre comment les algorithmes de conversion fonctionnent, il est utile d'utiliser la notion de « jour zéro » pour un mois donné. Le jour zéro est un jour virtuel situé avant le premier jour du mois et après le dernier jour du mois précédent. Ainsi, le 0 mars 2015 se situe après le 28 février 2015 et avant le 1 er mars 2015. Le fait que son Rata Die soit identique à celui du 28 février ne change rien au fait qu'il est censé se situer après le 28 février. Voici une fonction qui permet de construire le 0 janvier d'une année ou le 0 Vendémiaire d'une année : ∇ R ← calfr∆zerojanvnd Y R ← Y ∘.× 1 0 0 R ← R + (⍴R) ⍴ 0 1 0 ∇ calfr∆fr2rd - Conversion du calendrier républicain vers Rata Die Commençons par calculer le Rata Die d'une date du calendrier républicain. Il faut ajouter les termes suivants : 654414, qui est le Rata Die du zéro Vendémiaire I, (AAAA - 1) × 365, le nombre de jours du zéro Vendémiaire I au zéro Vendémiaire de l'année demandée, en oubliant les jours bissextiles, c'est-à-dire les « 6 jour complémentaire », calfr∆frbis(AAAA), qui compte combien d'années bissextiles ont précédé l'année demandée, (MM - 1) × 30, le nombre de jours du zéro Vendémiaire au jour zéro du mois demandé, JJ, pour arriver finalement au jour demandé. En fait, on rassemble toutes les constantes additives en une seule, ce qui donne le calcul suivant : AAAA × 365, calfr∆frbis(AAAA), MM × 30, JJ, constante additive. ∇ R ← calfr∆fr2rd DATE R ← 654019 + ( calfr∆frbis calfr∆year DATE) + DATE +.× 365 30 1 ∇ calfr∆frbis - Nombre d'années bissextiles avant l'année N (calendrier républicain) Cette fonction donne le nombre d'années bissextiles qui ont eu lieu avant l'année en paramètre. Elle permet d'affiner le calcul de la date, par rapport à l'estimation obtenue en prenant des années à 365 jours. La règle pour les années bissextiles était une règle astronomique jusqu'en l'an XX, le premier Vendémiaire devant coïncider avec l'équinoxe d'automne. Ensuite, la réforme de Gilbert Romme aurait fait appliquer une règle arithmétique analogue à celle du calendrier grégorien. La règle de Romme indique qu'une année est bissextile si elle est divisible par 4, sauf si elle est divisible par 100, mais elle l'est quand même si elle est divisible par 400, sauf si elle est divisible par 4000. Voici la comparaison des deux règles pour le début de l'ère républicaine. Les deux colonnes « arithmétique » simulent l'hypothèse où la règle arithmétique aurait été en vigueur dès le début. Les deux colonnnes « astronomique » présentent le cas réel : règle astronomique au début et règle arithmétique ensuite. Les colonnes « Bis ? » indiquent par un « X » si l'année est bissextile en fonction de la règle utilisée. Les colonnes « frbis » indiquent le nombre d'années bissextiles avant l'année considérée, ce qui correspond au résultat de la fonction calfr∆frbis . Arithmétique Astronomique Année Bis ? frbis Bis ? frbis 1 0 0 2 0 0 3 0 x 0 4 x 0 1 5 1 1 6 1 1 7 1 x 1 8 x 1 2 9 2 2 10 2 2 11 2 x 2 12 x 2 3 13 3 3 14 3 3 15 3 x 3 16 x 3 4 17 4 4 18 4 4 19 4 4 20 x 4 x 4 21 5 5 22 5 5 23 5 5 24 x 5 x 5 25 6 6 En fait, les deux règles n'engendrent une différence que pour les années IV, VIII, XII et XVI. Donc le sous-programme effectue le calcul avec la règle arithmétique dès l'an I, puis rectifie le résultat si l'on a l'une de ces quatre années. N'oubliez pas que le sous-programme commence par soustraire 1 à l'année, c'est pour cela qu'il teste les valeurs 3, 7, 11 et 15. ∇ R ← calfr∆frbis YEAR YEAR ← YEAR - 1 R ← - / ⌊ YEAR ∘.÷ 4 100 400 4000 R ← R + YEAR ∈ 3 7 11 15 ∇ calfr∆gr2rd - Conversion du calendrier grégorien vers Rata Die Malgré les critères pour les années bissextiles, la conversion du calendrier républicain vers le Rata Die est simple, comparée avec la fonction correspondante du calendrier grégorien. En effet, la période bouche-trou (jours complémentaires) est à la fin de l'année donc sa longueur variable et plus faible que les mois normaux n'a pas d'influence sur les calculs. En revanche, dans le calendrier grégorien, le mois bouche-trou, février, apparaît au début de l'année et complique le calcul pour les mois suivants. De plus, la longueur des autres mois est variable : 30 ou 31 jours. C'est pourquoi nous introduisons un nouveau calendrier, le « calendrier grégorien décalé ». Dans ce calendrier, les mois de janvier et février sont transférés à la fin de l'année précédente et l'année commence au 1 er mars. De plus, pour les raisons exposées ci-dessous, les mois sont numérotés de 4 (mars) à 15 (février), pour la raison exposée ci-dessous. Ainsi le 28 février 2015 devient 2014 15 28 et le premier mars 2015 devient 2015 4 1 . Dans le tableau ci-dessous, la partie gauche s'intéresse au nombre de mois à 31 jours qui précèdent le mois courant dans l'année décalée. La partie droite explique le calcul du nombre de jours depuis le zéro mars jusqu'au jour zéro du mois courant. M nb31 M 0.6 × M ¯2 + ⌊ 0.6 × M M ln nb 30.6 × M ¯122 + ⌊ 30.6 × M M 0 4 2.4 0 M 31 0 122.4 0 A 1 5 3.0 1 A 30 31 153.0 31 M 1 6 3.6 1 M 31 61 183.6 61 J 2 7 4.2 2 J 30 92 214.2 92 J 2 8 4.8 2 J 31 122 244.8 122 A 3 9 5.4 3 A 31 153 275.4 153 S 4 10 6.0 4 S 30 184 306.0 184 O 4 11 6.6 4 O 31 214 336.6 214 N 5 12 7.2 5 N 30 245 367.2 245 D 5 13 7.8 5 D 31 275 397.8 275 J 6 14 8.4 6 J 31 306 428.4 306 F 7 15 9.0 7 F 28? 29? 337 459.0 337 Voici donc la fonction : ∇ R ← calfr∆gr2rd DATE; DIM DIM ← ⍴ DATE DATE←(DIM ⍴0 1 0) + DATE + (2≥ calfr∆month DATE) ∘.× ¯1 12 0 R ← ¯428 + (-/ ⌊ ( calfr∆year DATE) ∘.÷ 4 100 400) + ⌊DATE +.× 365 30.6 1 ∇ calfr∆rd2fr - Conversion du Rata Die vers le calendrier républicain Principe : en partant de la valeur Rata Die , la fonction évalue une fourchette pour l'année, qui peut donc s'étaler de YL à YH . Supposons que l'on parte de la valeur Rata Die 672800, avec une fourchette de 50 à 53. Le sous-programme construit ensuite la liste YR des années de la fourchette, soit dans l'exemple un vecteur YR valant 50 51 52 53 . Puis le sous-programme transforme ce vecteur d'années en vecteurs de dates DR , correspondant au zéro Vendémiaire de chaque année, ce qui donnerait : DR 50 1 0 51 1 0 52 1 0 53 1 0 La fonction calfr∆fr2rd convertit cela en Rata Die NR 672311 672676 673041 673407 et compare avec la valeur initiale 672800, ce qui donne : CM 1 1 0 0 Cela permet d'avoir l'année de la date en prenant l'année la plus élevée pour laquelle la valeur dans NR est inférieure à la valeur du paramètre d'entrée N . Dans l'exemple ci-dessus, on en déduit que l'année est 51. En faisant la différence des deux valeurs Rata Die , on obtient 124, ce qui est facilement converti en 4 Pluviôse ( 5 4 ) avec de simples divisions par 30. Remarque : dans l'exemple ci-dessus, la plage d'années avait 4 valeurs. Dans la réalité, la plage n'aura qu'une seule valeur, parfois deux au voisinage des changements d'année. Le choix de 4 valeurs avait un rôle pédagogique. En fait, la première date pour laquelle la plage comporte trois valeurs est l'année 3744 et il faut attendre 7480 pour qu'elle compte quatre valeurs. Autre remarque : lorsque le paramètre en entrée n'est pas un scalaire, mais un vecteur, un tableau ou une structure d'ordre plus élevé, les variables intermédiaires ont également un ordre plus élevé. Le seul point délicat est de savoir ce qui se passe lorsque l'une des valeurs Rata Die donne une plage de 1 valeur et l'autre une plage de 2 valeurs (par exemple). Dans ce cas, la plage de valeurs du premier Rata Die est allongée à 2 valeurs pour conserver la rectangularité de la variable YR . ∇ R ← calfr∆rd2fr N; ⎕IO; N1; YH; YL; YI; YR; DR; NR; CM; Y; M; D ⎕IO ← 1 N1 ← N - 654414 YH ← ⌈ N1 ÷ 365.24 YL ← ⌈ N1 ÷ 365.34 YI ← 0 , ⍳ ⌈/,YH-YL YR ← YL ∘.+ YI DR ← calfr∆zerojanvnd YR NR ← calfr∆fr2rd DR CM ← NR < N ∘.+ (⍴YI)⍴0 Y ← ⌈/YR×CM D ← N - ⌈/NR×CM M ← ⌈D÷30 D ← D - 30 × M - 1 R ← (Y ∘.× 1 0 0) + (M ∘.× 0 1 0) + D ∘.× 0 0 1 ∇ Résumé des variables locales : YH year (high) borne supérieure de la plage d'années YL year (low) borne inférieure de la plage d'années YI year increments vecteur d'incréments pour construire la plage d'années YR year range plage d'années DR date range plage de dates (0 Vendémiaire) NR number range plage de nombres ( Rata Die ) CM comparison résultat de la comparaison Y year final value valeur finale de l'année D day final value valeur finale du jour M month final value valeur finale du mois Voici un exemple d'exécution avec un vecteur en entrée. Notons que pour le premier nombre, la plage de valeurs de la date comportait une seule année, l'année 400. Mais par « contamination » de la dernière valeur, cette plage a été étendue à trois années. V←800505 800511 800879 2115019 calfr∆rd2fr V 400 12 30 400 13 6 402 1 3 4000 1 1 YH 400 401 402 4000 YL 400 400 401 3998 YI 0 1 2 YR 400 401 402 400 401 402 401 402 403 3998 3999 4000 DR 400 1 0 401 1 0 402 1 0 400 1 0 401 1 0 402 1 0 401 1 0 402 1 0 403 1 0 3998 1 0 3999 1 0 4000 1 0 NR 800145 800511 800876 800145 800511 800876 800511 800876 801241 2114288 2114653 2115018 CM 1 0 0 1 0 0 1 1 0 1 1 1 Y 400 400 402 4000 M 12 13 1 1 D 30 6 3 1 calfr∆rd2gr - Conversion du Rata Die vers le calendrier grégorien Pour cette fonction, il y a deux possibilités. La première consiste à convertir le Rata Die en grégorien décalé, puis le grégorien décalé en grégorien. Ou alors, convertir directement en grégorien en utilisant deux fois le mécanisme de plage de valeurs possibles utilisé dans calfr∆rd2fr , une première fois pour calculer l'année, la seconde fois pour calculer le mois. C'est cette deuxième possibilité que j'ai choisie. Le calcul de la borne supérieure et de la borne inférieure de la plage de mois nécessite une division par 29,5 et une division par 31. Du coup, l'estimation du mois est beaucoup moins précise que l'estimation de l'année. La plage aura donc trois valeurs dès que le nombre de jours vaut 620. Or, on sait que le nombre de jours ne dépassera pas 366 et que le numéro du mois ne dépassera pas 12. Dans ces conditions, la plage aura au maximum deux valeurs. Donc on ne s'embête pas, on prend toujours une plage à deux valeurs pour calculer le mois, même si l'estimation avait donné une plage à une seule valeur. ∇ R ← calfr∆rd2gr N; ⎕IO; YH; YL; YI; YR; DR; NR; CM; Y; M; D; ML; MR ⎕IO ← 1 YH ← ⌈ N ÷ 365.24 YL ← ⌈ N ÷ 365.25 YI ← 0 , ⍳ ⌈/,YH-YL YR ← YL ∘.+ YI DR ← calfr∆zerojanvnd YR NR ← calfr∆gr2rd DR CM ← NR < N ∘.+ (⍴YI)⍴0 Y ← ⌈/YR×CM D ← N - ⌈/NR×CM ML ← ⌈D÷31 MR ← ML ∘.+ 0 1 DR ← (Y ∘.× 2 3 ⍴ 1 0 0) + (MR ∘.× 0 1 0) NR ← calfr∆gr2rd DR CM ← NR < N ∘.+ 0 0 M ← ⌈/MR×CM D ← N - ⌈/NR×CM R ← (Y ∘.× 1 0 0) + (M ∘.× 0 1 0) + D ∘.× 0 0 1 ∇ Les fonctions de conversion calfr∆gr2fr - Conversion du calendrier grégorien vers le calendrier républicain Après tous ces calculs compliqués, la fonction de conversion est simplissime, un peu décevante. ∇ R ← calfr∆gr2fr D R ← calfr∆rd2fr calfr∆gr2rd D ∇ calfr∆fr2gr - Conversion du calendrier républicain vers le calendrier grégorien Idem pour l'autre fonction de conversion. ∇ R ← calfr∆fr2gr D R ← calfr∆rd2gr calfr∆fr2rd D ∇ Affichage des dates calfr∆prtfr - Affichage d'une date du calendrier républicain Rassembler les éléments de la date : nom du jour, numéro, nom du mois, etc, ne pose pas de problème. Ce qui en pose, c'est le fait que le résultat comporte des espaces superflus et qu'il faut les éliminer tout en conservant les espaces nécessaires. ∇ R ← calfr∆prtfr D; DAY; MONTH; CM; ⎕IO ⎕IO ← 1 DAY ← 10 8 ⍴ 'Décadi Primidi Duodi Tridi QuartidiQuintidiSextidi Septidi Octidi Nonidi ' R ← DAY[1 + 10 | calfr∆day D;] MONTH ← 13 11 ⍴ 'VendémiaireBrumaire Frimaire Nivôse Pluviôse Ventôse Germinal Floréal Prairial Messidor Thermidor Fructidor jour compl.' R ← R, ' ', (⍕ calfr∆day D), ' ', (MONTH[ calfr∆month D;]), ' ', ( calfr∆roman calfr∆year D), ', jour ', calfr∆feasts [¯30 + D +.× 0 30 1;] CM ← ' ' ≠ R R ← (CM ∨ 0,¯1↓CM) / R R ← (⌽∨\⌽R≠' ')/R ∇ calfr∆roman - Conversion d'un nombre en chiffres romains Si le nombre dépasse 3999, il conserve son expression en chiffres indo-arabes. Idem s'il est négatif ou nul. ∇ R ← calfr∆roman N; NODES → ((N>0) ∧ N<4000)/CONV R ← ⍕ N → 0 CONV: NODES ← 40 4 ⍴ ( calfr∆nodes 'IVX'), ( calfr∆nodes 'XLC'), ( calfr∆nodes 'CDM'), calfr∆nodes 'M??' R ← ,NODES[⎕IO + 30 20 10 0 + 10 10 10 10 ⊤ N;] R ← (R≠' ')/R ∇ calfr∆nodes - Construction des nœuds de la numération romaine Le terme « nœuds » provient de Histoire comparée des numérations écrites par Geneviève Guitel et je l'ai traduit en « nodes ». Dans une numération de base b , un nœud est un nombre de la forme k × b n , avec k entre 0 et b - 1. Cette fonction participe à la construction d'une chaîne de caractères comportant 10 nœuds de la base 10 écrit en chiffres romains. Chaque nœud est complété par des espaces pour avoir une longueur de 4. ∇ R ← calfr∆nodes CH R ← (' ', CH) [ ' IVX' ⍳ ' I II III IV V VI VII VIIIIX ' ] ∇ calfr∆feasts - Fêtes du calendrier républicain Cette fonction énumère les fêtes des 366 jours du calendier républicain. ∇ R ← calfr∆feasts; V ⍝ include here the contents of feasts ∇ Elle renvoie un tableau de 366 lignes de 21 caractères, une ligne par jour. 4 21↑calfr∆feasts du Raisin du Safran de la Châtaigne de la Colchique Tests internes calfr∆testdata - Données pour les tests Cette fonction renvoie un tableau de n lignes et 7 colonnes, contenant les données pour tester les fonctions de conversion. Chaque ligne contient la date grégorienne, au format AAAA MM JJ, la date républicaine au format AAAA MM JJ et la valeur Rata Die . Exemple : 2 7↑calfr∆testdata 1792 9 22 1 1 1 654415 1793 10 23 2 2 2 654811 Les premières lignes montrent que le 22 septembre 1792 correspond au 1 er Vendémiaire I avec une valeur Rata Die 654415. De même, le 23 octobre 1973 correspond au 2 Brumaire II, Rata Die 654811. Les valeurs adoptées sont les valeurs utilisées dans les tests de DateTime::Calendar::FrenchRevolutionary . Le programme qui les formatte avec la syntaxe APL est disponible sur GitHub . Et un utilitaire (en Perl) est fourni dans le présent projet pour insérer les valeurs dans le script final. ∇ R ← calfr∆testdata; V; L ⍝ include here the contents of testapl L ← (⍴ V) ÷ 7 R ← (L, 7) ⍴ V ∇ calfr∆teststring - Données alphanumériques de tests Cette fonction donne pour chaque ligne de calfr∆testdata le résultat attendu de la fonction calfr∆prtfr . Par exemple : 2 52↑calfr∆teststring Primidi 1 Vendémiaire I, jour du Raisin Duodi 2 Brumaire II, jour du Céleri L'origine des données et l'utilitaire pour les insérer dans le script sont les mêmes que pour calfr∆testdata . ∇ R ← calfr∆teststring; V; L V ← '' ⍝ include here the contents of testapl1 ∇ calfr∆alltests - Lancement de tous les tests ∇ calfr∆alltests calfr∆testfr2rd calfr∆testgr2rd calfr∆testrd2fr calfr∆testrd2gr calfr∆testgr2fr calfr∆testfr2gr calfr∆testprtfr ∇ calfr∆testfr2rd Cette fonction teste calfr∆fr2rd avec une variété de paramètres en entrée : deux dates scalaires, un vecteur de dates, un tableau de dates, jusqu'à une structure de dates de rang 7 (donc une structure d'entiers de rang 8). Les tests sont effectués une première fois avec ⎕IO à 1, une seconde fois avec ⎕IO à 0. Chaque test élémentaire tombant en erreur affiche un message. Si tous les tests élémentaires réussissent, la fonction principale de test affiche un seul message. ∇ calfr∆testfr2rd; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;7] PARAM ← calfr∆testdata [;4 5 6] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0fr2rd 1 OK ←OK ∧ calfr∆test0fr2rd 2 OK ←OK ∧ calfr∆test1fr2rd 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1fr2rd 5 5 OK ←OK ∧ calfr∆test1fr2rd 5 3 3 OK ←OK ∧ calfr∆test1fr2rd 5 2 2 2 OK ←OK ∧ calfr∆test1fr2rd 7 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆fr2rd : no errors' ∇ calfr∆test0fr2rd Cette fonction teste calfr∆fr2rd pour une date scalaire. ⎕IO est initialisé avec la variable globale IO , en fait une variable locale de la fonction appelante calfr∆testfr2rd transmise globalement, comme c'est le cas pour PARAM (paramètres à utiliser pour les fonctions) et EXPEC (résultat attendu ou expected result ). ∇ R ← calfr∆test0fr2rd N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N] PAR ← PARAM[N;] LIB ← 'Checking calfr∆fr2rd with scalar date ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆fr2rd PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDATA ⍝ no need to check dimension, it is the empty vector LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1fr2rd Cette fonction teste calfr∆fr2rd pour un vecteur de dates ou une structure de rang supérieur. ⎕IO est initialisé avec la variable globale IO , en fait une variable locale de la fonction appelante calfr∆testfr2rd transmise globalement. ∇ R ← calfr∆test1fr2rd DIM; LIB; EXP; GOT; NERR LIB ← 'Checking calfr∆fr2rd with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← DIM ⍴ EXPEC ⎕IO ← IO GOT ← calfr∆fr2rd (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testgr2rd ∇ calfr∆testgr2rd; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;7] PARAM ← calfr∆testdata [;1 2 3] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0gr2rd 1 OK ←OK ∧ calfr∆test0gr2rd 2 OK ←OK ∧ calfr∆test1gr2rd 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1gr2rd 5 5 OK ←OK ∧ calfr∆test1gr2rd 5 3 3 OK ←OK ∧ calfr∆test1gr2rd 5 2 2 2 OK ←OK ∧ calfr∆test1gr2rd 7 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆gr2rd : no errors' ∇ calfr∆test0gr2rd ∇ R ← calfr∆test0gr2rd N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N] PAR ← PARAM[N;] LIB ← 'Checking calfr∆gr2rd with scalar date ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆gr2rd PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDATA ⍝ no need to check dimension, it is the empty vector LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1gr2rd ∇ R ← calfr∆test1gr2rd DIM; LIB; EXP; GOT; NERR LIB ← 'Checking calfr∆gr2rd with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← DIM ⍴ EXPEC GOT ← calfr∆gr2rd (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testrd2fr ∇ calfr∆testrd2fr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;4 5 6] PARAM ← calfr∆testdata [;7] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0rd2fr 1 OK ←OK ∧ calfr∆test0rd2fr 2 OK ←OK ∧ calfr∆test1rd2fr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1rd2fr 3 3 OK ←OK ∧ calfr∆test1rd2fr 15 3 OK ←OK ∧ calfr∆test1rd2fr 2 3 3 OK ←OK ∧ calfr∆test1rd2fr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆rd2fr : no errors' ∇ calfr∆test0rd2fr ∇ R ← calfr∆test0rd2fr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N] LIB ← 'Checking calfr∆rd2fr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆rd2fr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1rd2fr ∇ R ← calfr∆test1rd2fr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆rd2fr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆rd2fr DIM ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testrd2gr ∇ calfr∆testrd2gr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;1 2 3] PARAM ← calfr∆testdata [;7] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0rd2gr 1 OK ←OK ∧ calfr∆test0rd2gr 2 OK ←OK ∧ calfr∆test1rd2gr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1rd2gr 3 3 OK ←OK ∧ calfr∆test1rd2gr 15 3 OK ←OK ∧ calfr∆test1rd2gr 2 3 3 → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆rd2gr : no errors' ∇ calfr∆test0rd2gr ∇ R ← calfr∆test0rd2gr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N] LIB ← 'Checking calfr∆rd2gr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆rd2gr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1rd2gr ∇ R ← calfr∆test1rd2gr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆rd2gr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆rd2gr DIM ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testgr2fr ∇ calfr∆testgr2fr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;4 5 6] PARAM ← calfr∆testdata [;1 2 3] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0gr2fr 1 OK ←OK ∧ calfr∆test0gr2fr 2 OK ←OK ∧ calfr∆test1gr2fr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1gr2fr 3 3 OK ←OK ∧ calfr∆test1gr2fr 15 3 OK ←OK ∧ calfr∆test1gr2fr 2 3 3 OK ←OK ∧ calfr∆test1gr2fr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆gr2fr : no errors' ∇ calfr∆test0gr2fr ∇ R ← calfr∆test0gr2fr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N;] LIB ← 'Checking calfr∆gr2fr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆gr2fr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1gr2fr ∇ R ← calfr∆test1gr2fr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking calfr∆gr2fr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆gr2fr (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testfr2gr ∇ calfr∆testfr2gr; IO; ⎕IO; OK; PARAM; EXPEC; RESUL ⎕IO ← 1 EXPEC ← calfr∆testdata [;1 2 3] PARAM ← calfr∆testdata [;4 5 6] OK ← 1 IO ← 2 LOOP: IO ← IO - 1 ⎕IO ← IO OK ←OK ∧ calfr∆test0fr2gr 1 OK ←OK ∧ calfr∆test0fr2gr 2 OK ←OK ∧ calfr∆test1fr2gr 1 ↑ ⍴PARAM ⍝ checking with the full vector OK ←OK ∧ calfr∆test1fr2gr 3 3 OK ←OK ∧ calfr∆test1fr2gr 15 3 OK ←OK ∧ calfr∆test1fr2gr 2 3 3 OK ←OK ∧ calfr∆test1fr2gr 6 ⍴ 2 ⍝ checking max allowed rank → IO / LOOP → (OK=0) / 0 ⍝ exit if the errors are already reported 'Checking calfr∆fr2gr : no errors' ∇ calfr∆test0fr2gr ∇ R ← calfr∆test0fr2gr N; LIB; PAR; EXP; GOT; NERR ⎕IO ← 1 EXP ← EXPEC[N;] PAR ← PARAM[N;] LIB ← 'Checking calfr∆fr2gr with scalar RD value ', (⍕PAR), ' and ⎕IO ', ⍕IO ⎕IO ← IO GOT ← calfr∆fr2gr PAR → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank: expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimensions: expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆test1fr2gr ∇ R ← calfr∆test1fr2gr DIM; EXP; GOT; LIB; NERR LIB ← 'Checking fr2gr with dimension ', (⍕DIM), ' and ⎕IO ', ⍕IO EXP ← (DIM, 3) ⍴ EXPEC GOT ← calfr∆fr2gr (DIM, 3) ⍴ PARAM → ((⍴⍴EXP)=⍴⍴GOT)/CHKDIM LIB, ' Wrong rank, expected ', (⍕⍴⍴EXP), ', got ', ⍕⍴⍴GOT R ← 0 → 0 CHKDIM: → (∧/(⍴EXP)=⍴GOT)/CHKDATA LIB, ' Wrong dimension, expected ', (⍕⍴EXP), ', got ', ⍕⍴GOT R ← 0 → 0 CHKDATA: NERR ← +/,∨/EXP≠GOT → (NERR=0) / CHKIO LIB, ' Data errors: ', ⍕ NERR R ← 0 → 0 CHKIO: → (IO=⎕IO) / SUCCESS LIB, ' ⎕IO clobbered: was ', (⍕IO), ' became ', ⍕⎕IO R ← 0 → 0 SUCCESS: R ← 1 → 0 ∇ calfr∆testprtfr ∇ calfr∆testprtfr; TD; TS; I; IMAX; PAR; EXP; GOT; N; IO; ⎕IO IO ← 2 LOOPIO: IO ← IO - 1 'Checking calfr∆prtfr with the full vector (a bit slow) and ⎕IO ', ⍕IO ⎕IO ← 1 TD ← calfr∆testdata [; 4 5 6 ] TS ← calfr∆teststring I ← 0 N ← 0 IMAX ← (⍴ TS)[1] LOOP: ⎕IO ← 1 I ← I + 1 → (I > IMAX)/END PAR ← TD[I;] EXP ← TS[I;] EXP ← (⌽∨\⌽EXP≠' ')/EXP ⎕IO ← IO GOT ← calfr∆prtfr PAR → ((⍴ EXP) = ⍴ GOT)/NEXT 'Different length: ', (⍕⍴ EXP), ' ', ⍕⍴GOT 'Expected: ', EXP 'Got : ', GOT N ← N + 1 → LOOP NEXT: → (∧/EXP=GOT)/LOOP 'Different content' 'Expected: ', EXP 'Got : ', GOT N ← N + 1 → LOOP END: 'Data errors with ⎕IO = ', (⍕IO), ' : ', ⍕N → IO / LOOPIO ∇ Voir également Logiciels En Perl : DateTime::Calendar::FrenchRevolutionary également disponible sur GitHub . En Perl également : Date::Convert::French_Rev également disponible sur GitHub . Existe aussi en Ruby (mais ce n'est pas moi). Ou alors sous Emacs en e-LISP (les fioritures sont de moi, pas la substantifique moëlle). Existe sur Android (là encore, ce n'est pas moi). Existe aussi sur HP-48 et HP-50 ( dépôt GitHub ). Existe enfin sur HP-41 . Internet Forcément, l' entrée de Wikipedia. La FAQ de Claus Tondering (en anglais). L' entrée dans le site H2G2 (en anglais). Un site en français. Livres Quid 2001, M and D Frémy, éditions Robert Laffont. Agenda Républicain 197 (1988/89), éditions Syros Alternatives, ISBN 2 86738 262-9. N'importe quel livre scolaire consacré à l'Histoire de la Révolution française. The French Revolution, Thomas Carlyle, Oxford University Press, ISBN 0-19-281843-0, en anglais. Introduction à APL, S. Pommier, éditions Dunod, 1978, ISBN 2-04-010402-X. Apprendre et appliquer le langage APL, B. Legrand, éditions Masson, 1981, ISBN 2-225-69421-4. ]NEXTFILE GPL License GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! ...
http://www.gnu.org/savannah-checkouts/gnu/apl/Bits_and_Pieces/calfr.apl.html - [detail] - [similar]
PREV NEXT
Powered by Hyper Estraier 1.4.13, with 213331 documents and 1081073 words.