Pandigital Squares

September 29, 2020

Here is a simple test for pandigital-ness (is that a word?); it is slow, but fast enough for our purpose:

(define (pandigital? n)
(equal? (sort < (digits n)) (range 10)))

With that, it is easy to find pandigital squares:

> (define ps
(list-of (list n n2)
(n range 10000 100000)
(n2 is (* n n))
(pandigital? n2)))

> (length ps)
87

> ps
((32043 1026753849) (32286 1042385796) (33144 1098524736)
(35172 1237069584) (35337 1248703569) (35757 1278563049)
(35853 1285437609) (37176 1382054976) (37905 1436789025)
(38772 1503267984) (39147 1532487609) (39336 1547320896)
(40545 1643897025) (42744 1827049536) (43902 1927385604)
(44016 1937408256) (45567 2076351489) (45624 2081549376)
(46587 2170348569) (48852 2386517904) (49314 2431870596)
(49353 2435718609) (50706 2571098436) (53976 2913408576)
(54918 3015986724) (55446 3074258916) (55524 3082914576)
(55581 3089247561) (55626 3094251876) (56532 3195867024)
(57321 3285697041) (58413 3412078569) (58455 3416987025)
(58554 3428570916) (59403 3528716409) (60984 3719048256)
(61575 3791480625) (61866 3827401956) (62679 3928657041)
(62961 3964087521) (63051 3975428601) (63129 3985270641)
(65634 4307821956) (65637 4308215769) (66105 4369871025)
(66276 4392508176) (67677 4580176329) (68763 4728350169)
(68781 4730825961) (69513 4832057169) (71433 5102673489)
(72621 5273809641) (75759 5739426081) (76047 5783146209)
(76182 5803697124) (77346 5982403716) (78072 6095237184)
(78453 6154873209) (80361 6457890321) (80445 6471398025)
(81222 6597013284) (81945 6714983025) (83919 7042398561)
(84648 7165283904) (85353 7285134609) (85743 7351862049)
(85803 7362154809) (86073 7408561329) (87639 7680594321)
(88623 7854036129) (89079 7935068241) (89145 7946831025)
(89355 7984316025) (89523 8014367529) (90144 8125940736)
(90153 8127563409) (90198 8135679204) (91248 8326197504)
(91605 8391476025) (92214 8503421796) (94695 8967143025)
(95154 9054283716) (96702 9351276804) (97779 9560732841)
(98055 9614783025) (98802 9761835204) (99066 9814072356))

We could have made this quicker. The range could start at 31623 instead of 10000, because the square of any number less than 31623 has less than ten digits. And the test of pandigital-ness could be improved, perhaps using a bitvector and a fast function to take a bitcount. But that doesn’t matter. The program shown above was written as quickly as my fingers could type it, is absolutely clear and easily readable, and worked right the first time it was run, in a reasonable amount of time (less than a tenth of a second); you can’t ask for much more than that.

You can run the program at https://ideone.com/lSqLVG.

Pages: 1 2

6 Responses to “Pandigital Squares”

  1. Zack said

    Cute little exercise. Here is my take on it in Julia 1.5: https://pastebin.com/XV0aiT9j

    Please excuse the unnecessary use of semicolons here. I’ve gotten into the habit of using them everywhere, ever since I started learning another language that requires them. Cheers!

  2. Ernie said

    No need to test all integers from 35000 to 100000. Since all pandigitals are divisible by 9, we only need test integers divisible by 3 and exclude those ending in 0

  3. Zack said

    @Ernie. Good point! I’ve amended my code to take into account this information. Thank you for the tip!

  4. Jan Van lent said
    [ i**2 for i in range(int(1023456789**0.5), int(9876543210**0.5)) if len(set(str(i**2))) == 10 ]
    
  5. Daniel said

    Here’s a solution in C.

    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MIN_PANDIGITAL 1023456789
    #define MAX_PANDIGITAL 9876543210
    
    static bool is_pandigital(int64_t x) {
      if (x < MIN_PANDIGITAL || x > MAX_PANDIGITAL)
        return false;
      int count[10] = {0};
      for (int i = 0; i < 10; ++i) {
        int r = x % 10;
        if (++(count[r]) > 1)
          return false;
        x /= 10;
      }
      return true;
    }
    
    int main(void) {
      int start = 31991;  // int(sqrt(MIN_PANDIGITAL))
      int end = 99380;  // int(sqrt(MAX_PANDIGITAL))
      for (int x = start; x <= end; ++x) {
        int64_t square = (int64_t)x * (int64_t)x;
        if (is_pandigital(square))
          printf("%ld\n", square);
      }
      return EXIT_SUCCESS;
    }
    

    Output:

    1026753849
    1042385796
    1098524736
    1237069584
    ...
    9351276804
    9560732841
    9614783025
    9761835204
    9814072356
    
  6. Daniel said

    Here’s a solution in OCaml.

    let is_pandigital x =
      let min = 1023456789
      and max = 9876543210 in
      if x < min || x > max then false
      else
        let rec is_pandigital' pending observed =
          if pending = 0 then true
          else
            let digit = pending mod 10 in
            let mask = 1 lsl digit in
            if (mask land observed) > 0 then false
            else is_pandigital' (pending / 10) (observed lor mask)
        in is_pandigital' x 0
    ;;
    
    let start = 31991
    and finish = 99380 in
    let rec loop i =
      if i > finish then ()
      else let square = i * i in
        if is_pandigital square then Printf.printf "%d\n" square;
        loop (i + 1) in
    loop start
    

    Output:

    1026753849
    1042385796
    1098524736
    1237069584
    ...
    9351276804
    9560732841
    9614783025
    9761835204
    9814072356
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: