x86-64 Machine Code, 24 bytes
6A 0A 5E 31 C9 89 F8 99 F7 F6 01 D1 85 C0 75 F7 8D 04 09 99 F7 F7 92 C3
The above code defines a function in 64-bit x86 machine code that determines whether the input value is divisible by double the sum of its digits. The function conforms to the System V AMD64 calling convention, so that it is callable from virtually any language, just as if it were a C function.
It takes a single parameter as input via the EDI register, as per the calling convention, which is the integer to test. (This is assumed to be a positive integer, consistent with the challenge rules, and is required for the CDQ instruction we use to work correctly.)
It returns its result in the EAX register, again, as per the calling convention. The result will be 0 if the input value was divisible by the sum of its digits, and non-zero otherwise. (Basically, an inverse Boolean, exactly like the example given in the challenge rules.)
Its C prototype would be:
int DivisibleByDoubleSumOfDigits(int value);
Here are the ungolfed assembly language instructions, annotated with a brief explanation of the purpose of each instruction:
; EDI == input value
DivisibleByDoubleSumOfDigits:
push 10
pop rsi ; ESI <= 10
xor ecx, ecx ; ECX <= 0
mov eax, edi ; EAX <= EDI (make copy of input)
SumDigits:
cdq ; EDX <= 0
div esi ; EDX:EAX / 10
add ecx, edx ; ECX += remainder (EDX)
test eax, eax
jnz SumDigits ; loop while EAX != 0
lea eax, [rcx+rcx] ; EAX <= (ECX * 2)
cdq ; EDX <= 0
div edi ; EDX:EAX / input
xchg edx, eax ; put remainder (EDX) in EAX
ret ; return, with result in EAX
In the first block, we do some preliminary initialization of registers:
PUSH+POP instructions are used as a slow but short way to initialize ESI to 10. This is necessary because the DIV instruction on x86 requires a register operand. (There is no form that divides by an immediate value of, say, 10.)
XOR is used as a short and fast way to clear the ECX register. This register will serve as the "accumulator" inside of the upcoming loop.
- Finally, a copy of the input value (from
EDI) is made, and stored in EAX, which will be clobbered as we go through the loop.
Then, we start looping and summing the digits in the input value. This is based on the x86 DIV instruction, which divides EDX:EAX by its operand, and returns the quotient in EAX and the remainder in EDX. What we'll do here is divide the input value by 10, such that the remainder is the digit in the last place (which we'll add to our accumulator register, ECX), and the quotient is the remaining digits.
- The
CDQ instruction is a short way of setting EDX to 0. It actually sign-extends the value in EAX to EDX:EAX, which is what DIV uses as the dividend. We don't actually need sign-extension here, because the input value is unsigned, but CDQ is 1 byte, as opposed to using XOR to clear EDX, which would be 2 bytes.
- Then we
DIVide EDX:EAX by ESI (10).
- The remainder (
EDX) is added to the accumulator (ECX).
- The
EAX register (the quotient) is tested to see if it is equal to 0. If so, we have made it through all of the digits and we fall through. If not, we still have more digits to sum, so we go back to the top of the loop.
Finally, after the loop is finished, we implement number % ((sum_of_digits)*2):
The LEA instruction is used as a short way to multiply ECX by 2 (or, equivalently, add ECX to itself), and store the result in a different register (in this case, EAX).
(We could also have done add ecx, ecx+xchg ecx, eax; both are 3 bytes, but the LEA instruction is faster and more typical.)
- Then, we do a
CDQ again to prepare for division. Because EAX will be positive (i.e., unsigned), this has the effect of zeroing EDX, just as before.
- Next is the division, this time dividing
EDX:EAX by the input value (an unmolested copy of which still resides in EDI). This is equivalent to modulo, with the remainder in EDX. (The quotient is also put in EAX, but we don't need it.)
- Finally, we
XCHG (exchange) the contents of EAX and EDX. Normally, you would do a MOV here, but XCHG is only 1 byte (albeit slower). Because EDX contains the remainder after the division, it will be 0 if the value was evenly divisible or non-zero otherwise. Thus, when we RETurn, EAX (the result) is 0 if the input value was divisible by double the sum of its digits, or non-zero otherwise.
Hopefully that suffices for an explanation.
This isn't the shortest entry, but hey, it looks like it beats almost all of the non-golfing languages! :-)
Good challenge, welcome to PPCG! – Skidsdev – 2017-07-03T13:59:13.087
@Mayube Thanks, it is my second challenge, but the first one got closed :P – None – 2017-07-03T14:00:13.563
Are we allowed to take digits as a list of Integers? – Henry – 2017-07-03T14:32:32.223
4@Henry No, that would be way too trivial – None – 2017-07-03T14:34:47.657
Would outputting
0fortrueand any other number forfalsebe allowed? – Shaggy – 2017-07-03T15:42:38.537@Shaggy "The truthy / falsy values do not necessarily have to be constant, as long as for truthy you have a finite set of values, and their complement for the falsy ones." - so you have the set
{0}for truthy and its complement,Z \ {0}for false. Hence, I think it is allowed. – Mr. Xcoder – 2017-07-03T16:32:07.303@Shaggy Sorry for the delay I answered: Yes, it is allowed. – None – 2017-07-03T16:33:39.753
Why does the truthy set have to be finite? – CalculatorFeline – 2017-07-03T21:46:56.853
1Indeed, the two sentences of "Instead of truthy / falsy values for the true and false cases, you may instead specify any finite set of values for the true case, and their complement for the falsy ones. For a simple example, you may use 0 for the true case and all other numbers for the false case (or vice versa, if you like)" seem to contradict each other (in particular, the "finite" and the "or vice versa"). – Greg Martin – 2017-07-04T02:52:33.663
@CalculatorFeline You can have the falsy set finite and its complement truthy – None – 2017-07-04T11:31:50.720
In my opinion, all calculate-able set should be accepted. (that is, there exists a Turing machine which, given an output, output True or False deterministically within a finite time.) For example, True = odd number, False = even number. – user202729 – 2017-07-04T12:01:04.453