ARM Thumb, multiword integer, ~1.157921e+77 ~4.973232e+86
Machine code:
2306 1fd9 000a b407 b407
Assembly
.globl main
.thumb
.thumb_func
main:
push {r4, lr}
// start number generation code
movs r3, #6 // 2
subs r1, r3, #7 // 4
movs r2, r1 // 6
push {r1, r2, r3} // 8
push {r1, r2, r3} // 10
// end number generation code
// now printf everything
adr r0, .Lprintf_str
bl printf
pop {r1, r2, r3}
pop {r1, r2, r3, r4, pc}
// print 32 bits at a time
.Lprintf_str:
.asciz "%#08x%08x%08x%08x%08x%08x%08x%08x%08x\n"
Try it online! (sorta)
Assembles a 288-bit big endian unsigned integer (with little endian words) with the high 96 bits in r1-r3
and the low 192 bits on the stack.
The number is, in hex, 0xffffffffffffffff00000006ffffffffffffffff00000006ffffffffffffffff00000006
, or in base 10, 497323236409786642128422301523609912453495901056838330362914156057471888398396751347718
.
Explanation
You may be wondering why I chose 6
and 7
. The reason is because of the limitations of narrow instructions.
movs Rd, #imm
can only encode an 8-bit immediate from 0-255
. No negatives allowed, which would make this almost too easy.
subs Rd, Rn, #imm
can only encode a 3-bit immediate from 0-7
. I can only subtract 0-255
if I use the same destination register, which isn't very helpful.
So therefore, since r1
will be more significant, we put 6
in r3
, then subtract 7
to get -1
, or 0xFFFFFFFF
, in r1
.
movs r3, #6 // 2
subs r1, r3, #7 // 4
Now, time for things to get super dumb.
First, we duplicate 0xFFFFFFFF
to r2
using movs
.
movs r2, r1 // 6
Then, we (ab)use ARM's push
instruction. ARM's push
instruction (as well as its sibling stm
) can push multiple registers at once to the stack, effectively doing a block copy.
We abuse this to copy r1
, r2
, and r3
to the stack twice, tripling the width of the integer.
You could say this is some form of exponentiation, but all I'm doing is pushing to the stack. Nothing suspicious here. 😇
push {r1, r2, r3} // 8
push {r1, r2, r3} // 10
Now, it looks like this:
r1: 0xFFFFFFFF r2: 0xFFFFFFFF
r3: 0x00000006
sp+0: 0xFFFFFFFF sp+4: 0xFFFFFFFF
sp+8: 0x00000006 sp+12: 0xFFFFFFFF
sp+16: 0xFFFFFFFF sp+20: 0x00000006
ARM Thumb-2, softfloat, 1.797693e+308
Machine code:
f248 0310 041b 17da 43db
Assembly:
.thumb
.globl main
.thumb_func
main:
push {r4, lr}
// Begin number generation code
movw r3, #0x8010 // 4
lsls r3, r3, #16 // 6
asrs r2, r3, #31 // 8
mvns r3, r3 // 10
// End number generation code
adr r0, .printf_str
bl printf
pop {r4, pc}
.align 4
.printf_str:
.asciz "%f\n"
Try it online! (sorta)
Creates the 64-bit constant 0x7fefffffffffffff
, which is DBL_MAX
, in r2-r3
(since the AAPCS aligns 64-bit integers to even registers)
Specifically, 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000
We do this by first putting ~(*(long long*)&DBL_MAX) >> 48
in r3
, shifting left by 16, doing an arithmetic shift right into r2
to make it 0xFFFFFFFF
, then do a one's complement to get r3
to 0x7fefffff
.
ARM Thumb-2, (non-competing), softfloat + printf merging, 2.148532e+319
Machine code:
f248 0110 0409 43ca 0013
Assembly:
.thumb
.globl main
.thumb_func
main:
push {r4, lr}
// Begin number generation code
movw r1, #0x8010 // 4
lsls r1, r1, #16 // 6
mvns r2, r1 // 8
movs r3, r2 // 10
// End number generation code
adr r0, .printf_str
bl printf
pop {r4, pc}
// Combine 0x80100000u (2148532224) with the same double we had before.
.printf_str:
.asciz "%u%f\n"
Try it online! (sorta)
This is obviously cheating, as it is actually generating an unsigned integer and a double and printing them together, but decided to add it for the lulz. 😂
It basically does this:
uint32_t r1 = (~0x7fef) & 0xffff;
// 0x80100000
r1 <<= 16;
uint32_t r2 = ~r1;
uint32_t r3 = r2;
// 0x7fefffff7fefffff
uint64_t r2r3 = r2 | ((uint64_t)r3 << 32);
double d = *(double*)&r2r3;
printf("%u%f\n", r1, d);
If it takes longer than an hour to run on any computer in the world, it's invalid.
is not objective. I could (theoretically) manufacture a computer that takes an hour to change one T-state \$\endgroup\$* 2^x
? \$\endgroup\$