O'Halloran numbers: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 42: Line 42:
lb < n AND ohalloran
lb < n AND ohalloran
DO
DO
FOR h FROM l TO half max area WHILE INT bh = b * h, lh = l * h;
FOR h FROM b TO half max area WHILE INT bh = b * h, lh = l * h;
INT sum = 2 * ( lb + bh + lh );
INT sum = 2 * ( lb + bh + lh );
sum <= n AND ( ohalloran := sum /= n )
sum <= n AND ( ohalloran := sum /= n )

Revision as of 18:40, 5 April 2023

O'Halloran numbers is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

For this task, for our purposes, a cuboid is a 3 dimensional object, with six rectangular faces, where all angles are right angles, opposite faces of the cuboid are equal, and where each dimension is a positive integer unit length. It will subsequently be referred to simply as a cuboid; but be aware that it references the above definition.

The surface area of a cuboid is two times the length times the width, plus two times the length times the height, plus two times the width times the height. A cuboid will always have an even integer surface area. The minimum surface area a cuboid may have is 6; one where the l, w, and h measurements are all 1.

  2 × ( l × w + w × h + h × l )
  2 × ( 1 × 1 + 1 × 1 + 1 × 1 ) = 6

Different cuboid configurations (may) yield different surface areas, but the surface area is always an integer and is always even.

A cuboid with l = 2, w = 1 h = 1 has a surface area of 10

  2 × ( 2 × 1 + 1 × 1 + 1 × 2 ) = 10

There is no configuration which will yield a surface area of 8.

There are 16 known even integer values below 1000 which can not be a surface area for any integer cuboid. It is conjectured, though not rigorously proved, that no others exist.

Task
  • Find and display the sixteen even integer values larger than 6 (the minimum cuboid area) and less than 1000

that can not be the surface area of a cuboid.

See also


ALGOL 68

As in the Phix and other samples, we only need to consider one arrangement of each l, b and h values.

BEGIN # find O'Halloran numbers - numbers that cannot be the surface area of  #
      #                           a cuboid with integer dimensions            #
    INT count        := 0;
    INT max area      = 1 000;
    INT half max area = max area OVER 2;
    FOR n FROM 8 BY 2 TO max area DO
        BOOL ohalloran := TRUE;
        FOR l TO half max area WHILE ohalloran DO
            FOR b FROM l TO half max area WHILE INT lb = l * b;
                                                lb < n AND ohalloran
            DO
                FOR h FROM b TO half max area WHILE INT bh = b * h, lh = l * h;
                                                    INT sum = 2 * ( lb + bh + lh );
                                                    sum <= n AND ( ohalloran := sum /= n )
                DO SKIP OD
            OD
        OD;
        IF ohalloran THEN
            print( ( " ", whole( n, 0 ) ) );
            count +:= 1
        FI
    OD
END
Output:
 8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

Arturo

found: select 6..998 => even?

loop 1..497 'l ->
    loop 1..l 'w [
        lw: l * w
        if lw >= 498 -> break
        loop 1..w 'h [
            sa: 2 * (lw + (w*h) + h*l)
            (sa < 1000)? -> 'found -- sa
                         -> break
        ]
    ]

print found
Output:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

BASIC

Rosetta Code problem: https://rosettacode.org/wiki/O%27Halloran_numbers

by Jjuanhdez, 02/2023

BASIC256

Translation of: FreeBASIC
maxArea = 1000
halfMaxArea = maxArea/2
dim T[halfMaxArea]       #table of half areas
for i = 0 to halfMaxArea-1
	T[i] = True          #assume all are O'kalloran numbers
next i
for l = 1 to maxArea
	for w = 1 to halfMaxArea
		for h = 1 to halfMaxArea
			suma = l*w + l*h + w*h
			if suma < halfMaxArea then T[suma] = False  #not an O'kalloran number
		next h
	next w
next l

print "All known O'Halloran numbers:"
for l = 6/2 to halfMaxArea-1
	if T[l] then print int(l*2); " ";
next l
Output:
All known O'Halloran numbers:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924 

FreeBASIC

Const maxArea = 1000, halfMaxArea = maxArea/2
Dim As Integer i, l, w, h, suma
Dim As Boolean T(halfMaxArea)       'table of half areas

For i = 0 To halfMaxArea-1
    T(i) = True                     'assume all are O'kalloran numbers
Next i

For l = 1 To maxArea
    For w = 1 To halfMaxArea
        For h = 1 To halfMaxArea
            suma = l*w + l*h + w*h
            If suma < halfMaxArea Then T(suma) = False  'not an O'kalloran number
        Next h, w, l

Print "All known O'Halloran numbers:"
Print "[";
For l = 6/2 To halfMaxArea-1
    If T(l) Then Print l*2; ",";
Next l
Print Chr(8); " ]"
Sleep
Output:
All known O'Halloran numbers:
[ 8, 12, 20, 36, 44, 60, 84, 116, 140, 156, 204, 260, 380, 420, 660, 924 ]

Yabasic

Translation of: FreeBASIC
maxArea = 1000
halfMaxArea = maxArea/2
dim T(halfMaxArea)             //table of half areas
for i = 0 to halfMaxArea-1
    T(i) = True                //assume all are O'kalloran numbers
next i
for l = 1 to maxArea
    for w = 1 to halfMaxArea
        for h = 1 to halfMaxArea
            suma = l*w + l*h + w*h
            if suma < halfMaxArea  T(suma) = False  //not an O'kalloran number
        next h
    next w
next l

print "All known O'Halloran numbers:"
print "[";
for l = 6/2 to halfMaxArea-1
    if T(l)  print l*2, ",";
next l
print chr$(8), "]"
Output:
All known O'Halloran numbers:
[8,12,20,36,44,60,84,116,140,156,204,260,380,420,660,924]

C

Translation of: Wren

More or less.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int main() {
    bool *found = calloc(1000, sizeof(bool)); // all false initially
    int i, l, w, h, lw, sa;
    for (l = 1; l < 498; ++l) {
        for (w = 1; w <= l; ++w) {
            lw = l * w;
            if (lw >= 498) break;
            for (h = 1; h <= w; ++h) {
                sa = (lw + w*h + h*l) * 2;
                if (sa < 1000) found[sa] = true;
            }
        }
    }
    printf("All known O'Halloran numbers:\n[");
    for (i = 6; i < 1000; i += 2) {
        if (!found[i]) printf("%d, ", i);
    }
    printf("\b\b]\n");
    free(found);
    return 0;
}
Output:
All known O'Halloran numbers:
[8, 12, 20, 36, 44, 60, 84, 116, 140, 156, 204, 260, 380, 420, 660, 924] 

FutureBasic

 
_maxArea = 1000
_halfMaxArea = 500

NSUInteger i, l, w, h, sum
BOOL table( _halfMaxArea )

// Populate boolean table
for i = 0 to _halfMaxArea - 1
  table( i ) = YES
next

for l = 1 to _maxArea
  for w = 1 to _maxArea
    for h = 1 to _halfMaxArea
      sum = l * w + l * h + w * h
      if sum < _halfMaxArea then table( sum ) = NO
    next
  next
next

printf @"All known O'Halloran numbers:"
for l = 6/2 to _halfMaxArea - 1
  if table( l ) then print l * 2,
next
print chr$(8),

HandleEvents
Output:
All known O'Halloran numbers:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924 

Go

Translation of: C
package main

import "fmt"

func main() {
    found := make([]bool, 1000) // all false initially
    for l := 1; l < 498; l++ {
        for w := 1; w <= l; w++ {
            lw := l * w
            if lw >= 498 {
                break
            }
            for h := 1; h <= w; h++ {
                sa := (lw + w*h + h*l) * 2
                if sa < 1000 {
                    found[sa] = true
                }
            }
        }
    }
    fmt.Printf("All known O'Halloran numbers:\n[")
    for i := 6; i < 1000; i += 2 {
        if !found[i] {
            fmt.Printf("%d, ", i)
        }
    }
    fmt.Printf("\b\b]\n")
}
Output:
All known O'Halloran numbers:
[8, 12, 20, 36, 44, 60, 84, 116, 140, 156, 204, 260, 380, 420, 660, 924] 

J

   require'stats'
   2*(3}.i.501)-.+/1 */\.(|:3 comb 42)-i:1
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

Here, we use combinations with repetitions to generate the various relevant cuboid side lengths. Then we multiply all three pairs of these side length combinations and sum the pairs. Then we remove these sums from the sequence 3..500, and finally we multiply the remaining 16 values by 2.

jq

Works with: jq

Also works with jaq and with gojq, the Go implementation of jq

# Emit a stream of possible cuboid areas less than or equal to the specified limit, 
# $maxarea, which should be an even integer.
def cuboid_areas(maxarea):
  maxarea as $maxarea
  # min area per face is 1 so if total area is $maxarea, the max dimension is ($maxarea-4)/2
  | ($maxarea/2) as $halfmax
  | ($halfmax - 2) as $max
  | foreach range(1; 1+$max) as $i (null;
      label $loopj
      # By symmetry, we can assume i <= j <= k
      | foreach range($i; 1+$max) as $j (.;
          ($i*$j) as $ij
          | if $ij + 2 > $halfmax then break $loopj else . end
	  | label $loopk
          | foreach range($j; 1+$max) as $k (.;
	      ($ij + $i*$k + $j*$k) as $total
              | if $total > $halfmax then break $loopk
	        else 2 * $total
		end) ) );

1000 as $n
| "Even integers greater than 6 but less than \($n) that cannot be cuboid surface areas:",
  [range(6;$n;2)] - [cuboid_areas($n-2)]
Even integers greater than 6 but less than 1000 that cannot be cuboid surface areas:
[8,12,20,36,44,60,84,116,140,156,204,260,380,420,660,924]

Julia

""" Rosetta code task: rosettacode.org/wiki/O%27Halloran_numbers """

const max_area, half_max = 1000, 500
const areas = trues(max_area)

areas[1:2:max_area] .= false

for i in 1:max_area
    for j in 1:half_max
        i * j > half_max && break
        for k in 1:half_max
            area = 2 * (i * j + i * k + j * k)
            area > max_area && break
            areas[area] = false
        end
    end
end

println("Even surface areas < $max_area NOT achievable by any regular integer-valued cuboid:\n",
    [n for n in eachindex(areas) if areas[n]])
Output:
Even surface areas < 1000 NOT achievable by any regular integer-valued cuboid:
[2, 4, 8, 12, 20, 36, 44, 60, 84, 116, 140, 156, 204, 260, 380, 420, 660, 924]

Perl

use v5.36;
my @A;
my $threshold = 10_000; # redonkulous overkill

for my $x (1..$threshold) {
    X: for my $y (1..$x) {
        last X if $x*$y > $threshold;
        Y: for my $z (1..$y) {
           last Y if (my $area = 2 * ($x*$y + $y*$z + $z*$x)) > $threshold;
           $A[$area] = "$x,$y,$z";
        }
    }

say 'Even integer surface areas NOT achievable by any regular, integer dimensioned cuboid';
for (0..$#A) {
    print "$_ " if $_ < $threshold and $_ > 6 and 0 == $_ % 2 and not $A[$_];
}
Output:
Even integer surface areas NOT achievable by any regular, integer dimensioned cuboid:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

Phix

Since we are going to check {1,1,2}, there is no point checking {1,2,1} or {2,1,1} etc.

with javascript_semantics
constant max_area = 1000, half_max = max_area/2
sequence areas = repeat(0,5)&tagset(max_area,6)

for x=1 to max_area do
    if odd(x) then areas[x] = 0 end if
    for y=x to floor(half_max/x) do
        for z=y to half_max do
            atom area = 2 * (x * y + x * z + y * z)
            if area > max_area then exit end if
            areas[area] = 0
        end for
    end for
end for

printf(1,"Even surface areas < %d NOT achievable by any regular integer-valued cuboid:\n%s\n",
         {max_area,join(filter(areas,"!=",0),fmt:="%d")})
Output:

You can also set max_area to 1,000,000 and get no more results.

Even surface areas < 1000 NOT achievable by any regular integer-valued cuboid:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

Python

Translation of: FreeBASIC
#!/usr/bin/python

maxArea = 1000
halfMaxArea = 500
T = []                           #table of half areas
for i in range(halfMaxArea):
    T.append(True)               #assume all are O'kalloran numbers

for l in range(1,maxArea):
    for w in range(1, halfMaxArea):
        for h in range(1, halfMaxArea):
            suma = l*w + l*h + w*h
            if suma < halfMaxArea:
                T[suma] = False  #not an O'kalloran number

print("All known O'Halloran numbers:")
for l in range(3,halfMaxArea):
    if T[l]:
        print(l*2, end=" ");
Output:
All known O'Halloran numbers:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

PROMAL

;;; find O'Halloran numbers - numbers that cannot be the surface area of
;;;                           a cuboid with integer dimensions
PROGRAM OHalloran
INCLUDE LIBRARY

CON WORD maxArea = 1000
WORD count
WORD halfMaxArea
WORD n
WORD l
WORD b
WORD h
WORD lb
WORD lh
WORD bh
WORD sum
BYTE isOHalloran
BEGIN
count = 0
halfMaxArea = maxArea / 2
n = 8
WHILE n <= maxArea
  isOHalloran = 1
  l = 1
  REPEAT
    b  = 1
    lb = l
    REPEAT
      h = 1
      REPEAT
        bh  = b * h
        lh  = l * h
        sum = 2 * ( lb + ( h * ( b + l ) ) )
        IF sum = n
          isOHalloran = 0
        h = h + 1
      UNTIL h > halfMaxArea OR sum > n OR NOT isOHalloran
      b  = b + 1
      lb = l * b
    UNTIL b > halfMaxArea OR lb >= n OR NOT isOHalloran
    l = l + 1
  UNTIL l > halfMaxArea OR NOT isOHalloran
  IF isOHalloran
    OUTPUT " #W", n
    count = count + 1
  n = n + 2
END
Output:
 8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

Raku

my @Area;

my $threshold = 1000; # a little overboard to make sure we get them all

for 1..$threshold -> $x {
    for 1..$x -> $y {
        last if $x × $y > $threshold;
        for 1..$y -> $z {
           push @Area[my $area = ($x × $y + $y × $z + $z × $x) × 2], "$x,$y,$z";
           last if $area > $threshold;
        }
    }
}

say "Even integer surface areas NOT achievable by any regular, integer dimensioned cuboid:\n" ~
   @Area[^$threshold].kv.grep( { $^key > 6 and $key %% 2 and !$^value } )»[0];
Output:
Even integer surface areas NOT achievable by any regular, integer dimensioned cuboid:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924

Wren

import "./seq" for Lst

var found = []
for (l in 1..497) {
    for (w in 1..l) {
        var lw = l * w
        if (lw >= 498) break
        for (h in 1..w) {
            var sa = (lw + w*h + h*l) * 2
            if (sa < 1000) found.add(sa) else break
        }
    }
}
var allEven = (6..998).where { |i| i%2 == 0 }.toList
System.print("All known O'Halloran numbers:")
System.print(Lst.except(allEven,found))
Output:
All known O'Halloran numbers:
[8, 12, 20, 36, 44, 60, 84, 116, 140, 156, 204, 260, 380, 420, 660, 924]

XPL0

int  L, W, H, HA, I;
char T(1000/2);                 \table of half areas
[for I:= 0 to 1000/2-1 do
        T(I):= true;            \assume all are O'Halloran numbers
for L:= 1 to 250 do
    for W:= 1 to 250/L do
        for H:= 1 to 250/L do
            [HA:= L*W + L*H + W*H;
            if HA < 500 then    \not an O'Halloran number
                T(HA):= false;
            ];
for I:= 6/2 to 1000/2-1 do
    if T(I) then
        [IntOut(0, I*2);  ChOut(0, ^ )];
]
Output:
8 12 20 36 44 60 84 116 140 156 204 260 380 420 660 924