AVR (274 bytes, 0 energy points)
With all those fancy high-level languages you're never really sure how much RAM you're accessing. The only way to be sure is to nuke it from orbit go down to the bytes. Fortunately I just happen to be teaching myself assembler at the moment.
This submission is a subroutine that uses the AVR-GCC calling convention. Fortunately it so happens that both the return value and the arguments fit in registers. The return value will be at most 12! + floor(pi * 10^11) = 0x49 41 e6 f2 4e
(five bytes) and each of the arguments is at most 12
(one byte each). Each size is rounded up to the nearest multiple of two, so we get a total size of 6 + 2 + 2 + 2 = 12
bytes. Starting at R25
, the return value fits in R20
-R24
, and the arguments live in R18
, R16
, and R14
.
Note that as per the rules ("... but you shall not change [the inputs].") I don't write to R18
, R16
, or R14
. I also don't explicitly use the stack or access anything other than the registers, meaning only two bytes are ever read from RAM during the whole program: RET
reads the return address from the stack. However, the rules state "language overheads don't count," so the total score is zero.
The only other oddity is that I don't have a printf
function, so in order to "yell" I bit-bang a generic parallel interface on port D. (That's digital pins 0-6 if you run this on an Arduino UNO, with pin 7 being the clock.)
Here is the code itself. All the jumps are relative, so you can plop this anywhere in your program and have it work.
4e e4 56 ef 69 e5 75 e2 89 e4 90 e0
22 24 23 94 33 24 44 24 55 24 77 24
60 2e 63 94 20 17 10 f4 22 24 12 c0
26 15 80 f0 56 9c 50 2c 46 9c 40 2c
51 0c 36 9c 30 2c 41 0c 57 1c 26 9c
20 2c 31 0c 47 1c 57 1c 63 94 ee cf
57 14 01 f5 47 14 f1 f4 37 14 e1 f4
2e 14 d0 f4 10 e5 1b b9 10 68 1b b9
19 e6 1b b9 10 68 1b b9 11 e2 1b b9
10 68 1b b9 1f 77 1b b9 10 68 1b b9
1f 77 1b b9 10 68 1b b9 1f 77 1b b9
10 68 1b b9 00 00 7b b8 1c e0 61 2e
6e 18 c9 f1 13 e3 81 9f 80 2d 91 2d
71 9f 70 2d 81 0d 97 1d 61 9f 60 2d
71 0d 87 1d 97 1d 51 9f 50 2d 61 0d
77 1d 87 1d 97 1d 41 9f 40 2d 51 0d
67 1d 77 1d 87 1d 97 1d 45 0f 56 1f
67 1f 78 1f 89 1f 97 1d 46 0f 57 1f
68 1f 79 1f 87 1d 97 1d 48 0f 59 1f
67 1d 77 1d 87 1d 97 1d 45 2f 56 2f
67 2f 78 2f 89 2f 99 27 86 95 77 95
67 95 57 95 47 95 6a 94 39 f6 42 0d
53 1d 64 1d 75 1d 87 1d 08 95
Here is the breakdown, including a short header to demonstrate calling the function.
0x0000 1fef ldi r17, 0xFF ; write 1111 1111
0x0002 1ab9 out 0x0a, r17 ; to port D direction register
0x0004 10e0 ldi r17, 0x00 ; write 0000 0000
0x0006 1bb9 out 0x0b, r17 ; to port D output register
0x0008 25e0 ldi r18, 0x05 ; set a to 5
0x000a 04e0 ldi r16, 0x04 ; set b to 4
0x000c 13e0 ldi r17, 0x03 ;
0x000e e12e mov r14, r17 ; set c to 3 (can't ldi, r14 < r16)
0x0010 0e940a00 call 0x14 ; call our subroutine @ 0x0014
0x0014 4ee4 ldi r20, 0x4E ; initialize output
0x0016 56ef ldi r21, 0xF6 ; with maximum 'pi integer'
0x0018 69e5 ldi r22, 0x59 ; Floor[Pi*10^11]
0x001a 75e2 ldi r23, 0x25 ; = 314 159 265 358 (12 digits)
0x001c 89e4 ldi r24, 0x49 ; = 0x 49 25 59 f6 4e
0x001e 90e0 ldi r25, 0x00
0x0020 2224 eor r2, r2 ; initialize x
0x0022 2394 inc r2 ; to 1
0x0024 3324 eor r3, r3 ; (eor clears a byte)
0x0026 4424 eor r4, r4
0x0028 5524 eor r5, r5
0x002a 7724 eor r7, r7 ; r7 stays zero (handy)
0x002c 602e mov r6, r16 ; count = b
0x002e 6394 inc r6 ; count++
0x0030 2017 cp r18, r16 ; if a >= b
0x0032 10f4 brcc .+4 ; go to loop @ 0x0038
0x0034 2224 eor r2, r2 ; otherwise x is zero
0x0036 12c0 rjmp .+36 ; go to end of loop @ 0x005c
0x0038 2615 cp r18, r6 ; if a < count
0x003a 80f0 brcs .+32 ; go to end of loop @ 0x005c
0x003c 569c mul r5, r6 ; otherwise multiply high byte by count
0x003e 502c mov r5, r0 ; copy low byte of result (high byte = 0)
0x0040 469c mul r4, r6 ; multiply second byte by count
0x0042 402c mov r4, r0
0x0044 510c add r5, r1 ; carry
0x0046 369c mul r3, r6 ; multiply third byte
0x0048 302c mov r3, r0
0x004a 410c add r4, r1
0x004c 571c adc r5, r7
0x004e 269c mul r2, r6 ; multiply low byte
0x0050 202c mov r2, r0
0x0052 310c add r3, r1
0x0054 471c adc r4, r7
0x0056 571c adc r5, r7
0x0058 6394 inc r6 ; count++
0x005a eecf rjmp .-36 ; return to start of loop @ 0x0038
0x005c 5714 cp r5, r7 ; if any of the high bytes of x
0x005e 01f5 brne .+64 ; are nonzero
0x0060 4714 cp r4, r7 ; then jump past 'yelling'
0x0062 f1f4 brne .+60 ; @ 0x00a0
0x0064 3714 cp r3, r7
0x0066 e1f4 brne .+56
0x0068 2e14 cp r2, r14 ; only the low byte is a comparison
0x006a d0f4 brcc .+52 ; since c is only one byte long
0x006c 10e5 ldi r17, 0x50 ; write 'P' to buffer
0x006e 1bb9 out 0x0b, r17 ; write to PORTD
0x0070 1068 ori r17, 0x80 ; set clock bit (buffer |= 1000 0000)
0x0072 1bb9 out 0x0b, r17 ; PORTD
0x0074 19e6 ldi r17, 0x69 ; 'i'
0x0076 1bb9 out 0x0b, r17 ; PORTD
0x0078 1068 ori r17, 0x80 ; 1000 0000
0x007a 1bb9 out 0x0b, r17 ; PORTD
0x007c 11e2 ldi r17, 0x21 ; '!'
0x007e 1bb9 out 0x0b, r17 ; PORTD
0x0080 1068 ori r17, 0x80 ; 1000 0000
0x0082 1bb9 out 0x0b, r17 ; PORTD
0x0084 1f77 andi r17, 0x7F ; clear clock bit (buffer &= 0111 1111)
0x0086 1bb9 out 0x0b, r17 ; PORTD
0x0088 1068 ori r17, 0x80 ; 1000 0000
0x008a 1bb9 out 0x0b, r17 ; PORTD
0x008c 1f77 andi r17, 0x7F ; 0111 1111
0x008e 1bb9 out 0x0b, r17 ; PORTD
0x0090 1068 ori r17, 0x80 ; 1000 0000
0x0092 1bb9 out 0x0b, r17 ; PORTD
0x0094 1f77 andi r17, 0x7F ; 0111 1111
0x0096 1bb9 out 0x0b, r17 ; PORTD
0x0098 1068 ori r17, 0x80 ; 1000 0000
0x009a 1bb9 out 0x0b, r17 ; PORTD
0x009c 0000 nop ; baud rate is 1/4 processor speed
0x009e 7bb8 out 0x0b, r7 ; PORTD
0x00a0 1ce0 ldi r17, 0x0C ; buffer = 12
0x00a2 612e mov r6, r17 ; count = buffer (# of places in p)
0x00a4 6e18 sub r6, r14 ; count -= c (# of /= 10 we need)
0x00a6 c9f1 breq .+114 ; if count == 0 skip loop @ 0x011a
0x00a8 13e3 ldi r17, 0x33 ; buffer = 51
0x00aa 819f mul r24, r17 ; following the same procedure as before
0x00ac 802d mov r24, r0 ; we multiply p by 51
0x00ae 912d mov r25, r1
0x00b0 719f mul r23, r17 ; since we can't divide by 10
0x00b2 702d mov r23, r0 ; we divide by 5
0x00b4 810d add r24, r1 ; by multiplying by
0x00b6 971d adc r25, r7 ; 0b0.00110011001100110011
0x00b8 619f mul r22, r17 ; equivalent to multiplying by
0x00ba 602d mov r22, r0 ; 0b110011 = 51
0x00bc 710d add r23, r1 ; then repeatedly adding to itself
0x00be 871d adc r24, r7 ; shifted right by one byte
0x00c0 971d adc r25, r7
0x00c2 519f mul r21, r17
0x00c4 502d mov r21, r0
0x00c6 610d add r22, r1
0x00c8 771d adc r23, r7
0x00ca 871d adc r24, r7
0x00cc 971d adc r25, r7
0x00ce 419f mul r20, r17
0x00d0 402d mov r20, r0
0x00d2 510d add r21, r1
0x00d4 671d adc r22, r7
0x00d6 771d adc r23, r7
0x00d8 871d adc r24, r7
0x00da 971d adc r25, r7
0x00dc 450f add r20, r21 ; add p to itself, shifted one byte
0x00de 561f adc r21, r22
0x00e0 671f adc r22, r23
0x00e2 781f adc r23, r24
0x00e4 891f adc r24, r25
0x00e6 971d adc r25, r7
0x00e8 460f add r20, r22 ; shifted two bytes
0x00ea 571f adc r21, r23
0x00ec 681f adc r22, r24
0x00ee 791f adc r23, r25
0x00f0 871d adc r24, r7
0x00f2 971d adc r25, r7
0x00f4 480f add r20, r24 ; shifted four bytes
0x00f6 591f adc r21, r25
0x00f8 671d adc r22, r7
0x00fa 771d adc r23, r7
0x00fc 871d adc r24, r7
0x00fe 971d adc r25, r7
0x0100 452f mov r20, r21 ; shift right one byte
0x0102 562f mov r21, r22
0x0104 672f mov r22, r23
0x0106 782f mov r23, r24
0x0108 892f mov r24, r25
0x010a 9927 eor r25, r25 ; clear top byte
0x010c 8695 lsr r24 ; finally divide by two
0x010e 7795 ror r23 ; by shifting right one bit
0x0110 6795 ror r22
0x0112 5795 ror r21
0x0114 4795 ror r20
0x0116 6a94 dec r6 ; count--
0x0118 39f6 brne .-114 ; if count != 0, repeat @ 0x00a8
0x011a 420d add r20, r2 ; add x to p
0x011c 531d adc r21, r3
0x011e 641d adc r22, r4
0x0120 751d adc r23, r5
0x0122 871d adc r24, r7
0x0124 0895 ret ; return
Note that the since the subroutine directly follows the main routine, the subroutine is actually executed twice. The second RET
call then tries to read from an empty stack. I left this behavior in the minimal example, since it's not a problem if you go step-by-step through the AVR simulator, and I wanted to keep the byte count low.
Mathematica (70 bytes, 6 energy points)
Function[{a,b,c},If[c>a!/b!,Print["Pi!!!!"]];a!/b!+Floor[Pi 10^(c-1)]]
a
, b
, and c
are 'free', and don't count towards the number of accesses.
- The string contains six characters, which count as six bytes.
Does the program count towards the RAM? If yes, how? – FUZxxl – 2015-04-12T14:24:51.297
2Is it "either yell Pi!!! or output the answer" or is it "potentially yell Pi!!! and always output the answer"? – Martin Ender – 2015-04-12T14:27:53.060
3What about languages where integers are of non-constant length? – orlp – 2015-04-12T16:53:26.640
5I have trouble understanding what you have to do (partly because of the strange language), I especially do not really understand the second yellow box, can anyone transcribe that to 'modern' english? Are a,b,c integers? What does 'equivalent' exactly mean here? – flawr – 2015-04-12T19:03:12.447
@orlp Then do the minimum size needed to contain them. For example, even though numbers in Mathematica are (mostly) arbitrary, the minimum number is 16 bytes. – LegionMammal978 – 2015-04-13T10:39:34.427
1I think that what is and is not a RAM access probably needs some clarification. Does our code exist in RAM? Do some or all of local varaibles? Do global variables? – Runer112 – 2015-04-13T14:00:30.967
O.P., have merci of us and please explain what and how do me count towards the energy usage, please. – Ismael Miguel – 2015-04-13T19:11:44.577
Is the division a floor division or floating-point division? That is, what if
a=1
andb=2
, shouldx
be equal to0.5
or0
? What is "the answer" that we should output? – 2012rcampion – 2015-04-13T19:36:41.943@LegionMammal978 What about machine integers in a packed array? – 2012rcampion – 2015-04-13T19:56:07.463
@2012rcampion Exactly what do you mean by "packed"? – LegionMammal978 – 2015-04-13T20:05:52.823
@LegionMammal978 See
Developer`PackedArrayQ
. Packed arrays use machine integers, so they're only 64 bits/8 bytes. – 2012rcampion – 2015-04-13T20:17:21.080@2012rcampion It only seems pack larger arrays (such as
Range[40]
.) – LegionMammal978 – 2015-04-13T20:18:06.123@LegionMammal978
Range[1]//PackedArrayQ
– 2012rcampion – 2015-04-13T20:26:47.970@LegionMammal978 Or
ConstantArray[_, 1]
to turn any integer or machine-precision number into a packed array. AlthoughByteCount
shows that the array actually takes up112
bytes, the question states that arrays are to be counted as the sum of their elements (8
in this case). – 2012rcampion – 2015-04-13T20:35:41.860FUZxxl no, its only for tie braking.
Martin: possibly yell pi, and always output.
flawr, a b and c are integers.
Runner. global and local variables count, your program doesnt. (exept for tie braking)
2012Champion a is always bigger than b, and if it isnt, then answer whatever. – matultimate – 2015-04-13T20:44:58.810
10^c
means10 XOR c
or10 * 10 * 10 ...
? – Ismael Miguel – 2015-04-13T21:47:44.170@IsmaelMiguel That was my modification, it means exponentiation. (The original spec said "an integer equivalent to pi to c places".) Actually now that you point it out, it looks like I made an off-by-one error (should be
10^(c-1)
, since forc=3
, it should bep=314
, not3141
). – 2012rcampion – 2015-04-13T23:42:19.350@2012rcampion It isn't well explicit. I'm doing by string accesses and cutting it. In math,
10^c
is totally different from10^c
in programming. – Ismael Miguel – 2015-04-14T08:08:23.593