Magic constant
A magic square is a square grid containing consecutive integers from 1 to N², arranged so that every row, column and diagonal adds up to the same number. That number is a constant. There is no way to create a valid N x N magic square that does not sum to the associated constant.
- EG
A 3 x 3 magic square always sums to 15.
┌───┬───┬───┐ │ 2 │ 7 │ 6 │ ├───┼───┼───┤ │ 9 │ 5 │ 1 │ ├───┼───┼───┤ │ 4 │ 3 │ 8 │ └───┴───┴───┘
A 4 x 4 magic square always sums to 34.
Traditionally, the sequence leaves off terms for n = 0 and n = 1 as the magic squares of order 0 and 1 are trivial; and a term for n = 2 because it is impossible to form a magic square of order 2.
- Task
- Starting at order 3, show the first 20 magic constants.
- Show the 1000th magic constant. (Order 1003)
- Find and show the order of the smallest N x N magic square whose constant is greater than 10¹ through 10¹⁰.
- Stretch
- Find and show the order of the smallest N x N magic square whose constant is greater than 10¹¹ through 10²⁰.
- See also
- Wikipedia: Magic constant
- OEIS: A006003 (Similar sequence, though it includes terms for 0, 1 & 2.)
Basic
QB64
<lang qbasic>$NOPREFIX
DIM order AS INTEGER DIM target AS INTEGER64
PRINT "First 20 magic constants:" FOR i = 3 TO 22
PRINT USING "####, "; MagicSum(i); IF i MOD 5 = 2 THEN PRINT
NEXT i PRINT PRINT USING "1000th magic constant: ##########,"; MagicSum(1002) PRINT PRINT "Smallest order magic square with a constant greater than:" FOR i = 1 TO 13 ' 64-bit integers can take us no further, unsigned or not
target = 10 ^ i DO order = order + 1 LOOP UNTIL MagicSum(order) > target PRINT USING "10^**: #####,"; i; order order = order * 2 - 1
NEXT i
FUNCTION MagicSum&& (n AS INTEGER)
MagicSum&& = (n * n + 1) / 2 * n
END FUNCTION</lang>
- Output:
First 20 magic constants: 15 34 65 111 175 260 369 505 671 870 1,105 1,379 1,695 2,056 2,465 2,925 3,439 4,010 4,641 5,335 1000th magic constant: 503,006,505 Smallest order magic square with a constant greater than: 10^*1: 3 10^*2: 6 10^*3: 13 10^*4: 28 10^*5: 59 10^*6: 126 10^*7: 272 10^*8: 585 10^*9: 1,260 10^10: 2,715 10^11: 5,849 10^12: 12,600 10^13: 27,145
Factor
<lang factor>USING: formatting io kernel math math.functions.integer-logs math.ranges prettyprint sequences ;
- magic ( m -- n ) dup sq 1 + 2 / * ;
"First 20 magic constants:" print 3 22 [a,b] [ bl ] [ magic pprint ] interleave nl nl "1000th magic constant: " write 1002 magic . nl "Smallest order magic square with a constant greater than:" print 1 0 20 [
[ 10 * ] dip [ dup magic pick < ] [ 1 + ] while over integer-log10 over "10^%02d: %d\n" printf dup + 1 -
] times 2drop</lang>
- Output:
First 20 magic constants: 15 34 65 111 175 260 369 505 671 870 1105 1379 1695 2056 2465 2925 3439 4010 4641 5335 1000th magic constant: 503006505 Smallest order magic square with a constant greater than: 10^01: 3 10^02: 6 10^03: 13 10^04: 28 10^05: 59 10^06: 126 10^07: 272 10^08: 585 10^09: 1260 10^10: 2715 10^11: 5849 10^12: 12600 10^13: 27145 10^14: 58481 10^15: 125993 10^16: 271442 10^17: 584804 10^18: 1259922 10^19: 2714418 10^20: 5848036
Julia
Uses the inverse of the magic constant function for the last part of the task. <lang julia>using Lazy
magic(x) = (1 + x^2) * x ÷ 2 magics = @>> Lazy.range() map(magic) filter(x -> x > 10) # first 2 values are filtered out println("First 20 magic constants: ", Int.(take(20, magics))) println("Thousandth magic constant is: ", collect(take(1000, magics))[end])
println("Smallest magic square with constant greater than:") for expo in 1:20
goal = big"10"^expo ordr = Int(floor((2 * goal)^(1/3))) + 1 println("10^", string(expo, pad=2), " ", ordr)
end
</lang>
- Output:
First 20 magic constants: [15, 34, 65, 111, 175, 260, 369, 505, 671, 870, 1105, 1379, 1695, 2056, 2465, 2925, 3439, 4010, 4641, 5335] Thousandth magic constant is: 503006505 Smallest magic square with constant greater than: 10^01 3 10^02 6 10^03 13 10^04 28 10^05 59 10^06 126 10^07 272 10^08 585 10^09 1260 10^10 2715 10^11 5849 10^12 12600 10^13 27145 10^14 58481 10^15 125993 10^16 271442 10^17 584804 10^18 1259922 10^19 2714418 10^20 5848036
Raku
<lang perl6>use Lingua::EN::Numbers:ver<2.8+>;
my @magic-constants = lazy (3..∞).hyper.map: { (1 + .²) * $_ / 2 };
put "First 20 magic constants: ", @magic-constants[^20]»., say "1000th magic constant: ", @magic-constants[999]., say "\nSmallest order magic square with a constant greater than:";
(1..20).map: -> $p {printf "10%-2s: %s\n", $p.&super, comma 3 + @magic-constants.first( * > exp($p, 10), :k ) }</lang>
- Output:
First 20 magic constants: 15 34 65 111 175 260 369 505 671 870 1,105 1,379 1,695 2,056 2,465 2,925 3,439 4,010 4,641 5,335 1000th magic constant: 503,006,505 Smallest order magic square with a constant greater than: 10¹ : 3 10² : 6 10³ : 13 10⁴ : 28 10⁵ : 59 10⁶ : 126 10⁷ : 272 10⁸ : 585 10⁹ : 1,260 10¹⁰: 2,715 10¹¹: 5,849 10¹²: 12,600 10¹³: 27,145 10¹⁴: 58,481 10¹⁵: 125,993 10¹⁶: 271,442 10¹⁷: 584,804 10¹⁸: 1,259,922 10¹⁹: 2,714,418 10²⁰: 5,848,036
Wren
This uses Julia's approach for the final parts though, as our BigInt class doesn't have a cube root function, we use Num (i.e. double precision floating point) arithmetic instead and then check that the answers are correct. <lang ecmascript>import "./seq" for Lst import "./fmt" for Fmt import "./big" for BigInt
var magicConstant = Fn.new { |n| (n*n + 1) * n / 2 }
var ss = ["\u2070", "\u00b9", "\u00b2", "\u00b3", "\u2074",
"\u2075", "\u2076", "\u2077", "\u2078", "\u2079"]
var superscript = Fn.new { |n| (n < 10) ? ss[n] : (n < 20) ? ss[1] + ss[n - 10] : ss[2] + ss[0] }
System.print("First 20 magic constants:") var mc20 = (3..22).map { |n| magicConstant.call(n) }.toList for (chunk in Lst.chunks(mc20, 10)) Fmt.print("$5d", chunk)
Fmt.print("\n1,000th magic constant: $,d", magicConstant.call(1002))
System.print("\nSmallest order magic square with a constant greater than:") for (i in 1..20) {
var goal = 10.pow(i) var order = ((goal * 2).cbrt).floor + 1 // accuracy check as we're using Num arithmetic to calculate the order var bigGoal = BigInt.ten.pow(i) var bigOrder = BigInt.new(order) if (!(magicConstant.call(bigOrder) > bigGoal && magicConstant.call(bigOrder-1) <= bigGoal)) { System.print("Order for 10^%(i) is inaccurate.") } Fmt.print("10$-2s : $,9i", superscript.call(i), order)
}</lang>
- Output:
First 20 magic constants: 15 34 65 111 175 260 369 505 671 870 1105 1379 1695 2056 2465 2925 3439 4010 4641 5335 1,000th magic constant: 503,006,505 Smallest order magic square with a constant greater than: 10¹ : 3 10² : 6 10³ : 13 10⁴ : 28 10⁵ : 59 10⁶ : 126 10⁷ : 272 10⁸ : 585 10⁹ : 1,260 10¹⁰ : 2,715 10¹¹ : 5,849 10¹² : 12,600 10¹³ : 27,145 10¹⁴ : 58,481 10¹⁵ : 125,993 10¹⁶ : 271,442 10¹⁷ : 584,804 10¹⁸ : 1,259,922 10¹⁹ : 2,714,418 10²⁰ : 5,848,036