It's funny how programming styles differ so much.
I wasn't trying to obfuscate; I was trying to be clear.
I want to multiply
d by something. Different somethings, depending on the value of
k. But always "
d *= something;". So that's what I wrote. I could have written
Code:
if ([i]k_satisfies_this_condition[/i])
d *= [i]this_value[/i];
else if ([i]k_satisfies_that_condition[/i])
d *= [i]that_value[/i];
else if ([i]k_satisfies_the_other_condition[/i])
d *= [i]the_other_value[/i];
else
d *= [i]yet_another_value[/i];
But that wouldn't make it explicit that the only difference between the different situations is the value by which
d gets multiplied while what's common to all of them is that
d gets multiplied by something.
Regarding indentation, is spreading things out really clearer than lining up the conditions in one "column" and the corresponding values in another? Or, analogously, would anyone write the above
if statements as follows?
Code:
if ([i]k_satisfies_this_condition[/i])
d *= [i]this_value[/i];
else
if ([i]k_satisfies_that_condition[/i])
d *= [i]that_value[/i];
else
if ([i]k_satisfies_the_other_condition[/i])
d *= [i]the_other_value[/i];
else
d *= [i]yet_another_value[/i];
Hmm. Probably some people would, actually, now that I think about it. But I prefer the former. The idea behind the code isn't really that of a binary choice, one branch of which happens to be another binary choice, etc. The idea is a sort of generalized
switch on
k, in which each case comprises a range of values rather than just a single value, but where all the cases are conceptually at the same "level". Pascal's
Case statement can do this, but C++'s
switch statement can't, so we need to simulate it using a bunch of deeply nested
if's. But we don't have to actually write them that way---deeply nested, that is---if doing so wouldn't express the underlying idea well, even though that's how the compiler interprets them.
Anyway, this is all just syntax. The interesting thing about the code, in my opinion, is the way it avoids overflow and underflow if at all possible, by interleaving the computations of
n!/
(n - r)!, 1/
r!,
pr, and (1 -
p)
n - r so as to keep
d, as long as possible, near 1, i.e., far from 0 or infinity.