Leap Years

29 views
Skip to first unread message

Skip Cave

unread,
Oct 10, 2025, 6:09:23 PM (5 days ago) Oct 10
to forum
Rules for leap years.
  1. If a year is divisible by 400, it is a leap year.
  2. If a year is divisible by 100 but not by 400, it is not a leap year.
  3. If a year is divisible by 4 but not by 100, it is a leap year.
  4. If a year is not divisible by 4, it is not a leap year.
Here's the J verb to find leap years:

m11=: 0: ~:/ .= 4 100 400"_ |/ ]

How does this work?
What does the |/ .] do?
What does the "_ do?
What does the .= do?
What does the ~:/ do?
What does the 0: do?

Skip


Skip Cave
Cave Consulting LLC

Pascal Jasmin

unread,
Oct 10, 2025, 9:38:42 PM (5 days ago) Oct 10
to 'Skip Cave' via forum
avoiding fancy use of . which documentation can explain but is best understood use is "magic for matrices", but from documentation is a "fancy form of @"

lets start with core function

   ( 4 100 400"_ |/ ]) 1996

0 96 396

( 4 100 400"_ |/ ]) 2000

0 0 0

The "_ is unnecessary in this fork.  Perhaps this was written before NVV was a thing?  But "_ turns a noun into a verb with constant output.

For a single argument |/ is unnecessary.  Just | works fine

   ( 4 100 400 |/ ]) 1996 2000

0 0

96 0

396 0

( 4 100 400 | ])("0) 1996 2000  NB. different shape than original function,  but still get's "core results"

0 96 396

0 0 0

how can we combine your rules to get right answer from the individual constraints?

is any one residue 0, is a start.

(0 = 4 100 400 | ])("0) 1996 1997 2000

1 0 0

0 0 0

1 1 1

  (0 ~:/@:= 4 100 400 | ])("0) 1996 1997 2000

1 0 1

~:/@: is maybe easier to understand than . version.

not equal inserted.

if not both 100 and 400 and then because 100 and 400 are both divisible by 4, result of 100&| ~: 400%&| not matching means if  4&| is = 0, then leap year, 

This is very special logic related to 3 constraints, where all leap years have first criteria true, and not both other 2 criteria.  I don't think this is a general field of research.


On Friday, October 10, 2025 at 06:09:24 p.m. EDT, 'Skip Cave' via forum <fo...@jsoftware.com> wrote:





Rules for leap years.
    1. If a year is divisible by 400, it is a leap year.
    2. If a year is divisible by 100 but not by 400, it is not a leap year.
    3. If a year is divisible by 4 but not by 100, it is a leap year.
    4. If a year is not divisible by 4, it is not a leap year.
Here's the J verb to find leap years:
From: https://code.jsoftware.com/wiki/JPhrases/DateTime

m11=: 0: ~:/ .= 4 100 400"_ |/ ]

How does this work?
What does the |/ .] do?
What does the "_ do?
What does the .= do?
What does the ~:/ do?
What does the 0: do?

Skip


Skip Cave
Cave Consulting LLC



To unsubscribe from this group and stop receiving emails from it, send an email to forum+un...@jsoftware.com.

Raul Miller

unread,
Oct 11, 2025, 12:11:50 AM (4 days ago) Oct 11
to fo...@jsoftware.com
Uh... I would argue that if a language primitive is not understood,
that should be an argument for better documentation and/or better
examples. Abandoning a long-standing primitive simply because you do
not feel comfortable with it seems like a dismal approach.

That said, there's also a problem here:

(0 ~:/@:= 4 100 400 | ]) 2000+i.10 10
|length error, executing dyad |

--
Raul

Skip Cave

unread,
Oct 11, 2025, 12:23:20 AM (4 days ago) Oct 11
to fo...@jsoftware.com
So a more straightforward leap year verb could be:

ly=.{{y#~(0 ~:/@:=4 100 400|])("0)y}}

Perhaps this version or something similar, should be put in place of the current m11 verb in the Date-Time example verbs?

Skip Cave
Cave Consulting LLC

Pascal Jasmin

unread,
Oct 11, 2025, 8:26:28 AM (4 days ago) Oct 11
to fo...@jsoftware.com
(0 ~:/@:= 4 100 400 | ])("0) 2000+i.10 10  NB. include rank 0


I was fairly proud/satisfied of my explanation.  There are some J primitives such as . and \ that are shortcuts for very specific rank combinations and/or @: @  Hooks are shortcuts for specific fork forms.


Rewriting into simpler primitive forms and then converting it to the shortcut version is a good approach to understanding J.  The more primitive versions are easier to think about.

The more interesting/tricky part of the function to me is the ~:/ logic

a full rank version that may be easier to understand

 (0 ~:/"1@:|:@:= 4 100 400 |/ ]) 2000+i.10 NB. does not match . when higher dimensional list.  ie. results are transposed. for 2000 + i.10 10


(0 ~:/"1&.:|:@:= 4 100 400 |/ ]) 2000+i.10 10  NB. matches (0 ~:/ . = 4 100 400 |/ ]) 2000+i.10 10 

trx2358...@yahoo.com

unread,
Oct 12, 2025, 2:29:19 AM (3 days ago) Oct 12
to Digest Recipients
I believe this is the version in FinnAPL (at least translated through K)

2|+/0=4 100 400|"_ 0]2024

As Pascal pointed out, divisible by anything in the list implies divisible by everything before it so you’re really only after the parity of the count.


Raul Miller

unread,
Oct 12, 2025, 6:54:02 PM (3 days ago) Oct 12
to fo...@jsoftware.com
Yes, generally speaking when one understands a variety of different
approaches (which reach the same end through different means) their
understanding is improved over when they just understood one of those
approaches.

Thanks,

--
Raul

On Sat, Oct 11, 2025 at 8:26 AM 'Pascal Jasmin' via forum

Pascal Jasmin

unread,
Oct 12, 2025, 8:43:24 PM (3 days ago) Oct 12
to trx2358-discord via forum
A full rank J version

(2 | 0 +/@:= 4 100 400 |/ ]) 2000+i.10 10

slightly slower than my original version


10 timespacex '(2 | 0 +/@:= 4 100 400 |/ ]) 2000+i.1000 1000'

0.00859761 4.61405e7

10 timespacex '(0 ~:/@:= 4 100 400 |/ ]) 2000+i.1000 1000'

0.00720412 4.1946e7

both much faster than rank 0 version

10 timespacex '(0 ~:/@:= 4 100 400 | ])("0) 2000+i.1000 1000'

0.10308 1.67791e7
Reply all
Reply to author
Forward
0 new messages