Decimal: ask to implement division (2nd attempt, I pressed enter too quickly x.x)

I think that perhaps we should ask the student to implement Division in this exercise. Here’s why.

The Exercise’s stand

The exercise’s instructions point out the following:

Despite Decimal being a custom type, we should still be able to treat them as numbers: the ==, <, >, +, -, and * operators should all work as expected on Decimals. For expediency, you are not required to implement division, as arbitrary-precision division can very quickly get out of hand. (How do you represent arbitrary-precision 1/3?)

Why the issue of arbitrary precision doesn’t translate to this exercise in particular

The exercise itself only asks the student to implement creation and arithmetic over this new type, Decimal.

This Decimal type needs to be:

  1. Buildable from a finite decimal expansion of a number (given as a &str in this case), and subsequently…
  2. Be able to be added, subtracted and multiplied together, as well as
  3. Be able to be compared to other Decimals, for both equality and ordering.

None of these properties actually require the type be able to represent the kind of precision implied in the instructions (a 0.3333333... recurring decimal). The only case in which I could see such things becoming a problem is if we were to ask them to produce a String representation of the Decimal.

Recurring decimals can’t really arise from those 3 properties since we don’t ask for division, and recurring decimals can’t be created from addition, subtraction and multiplication of finitely writeable decimals. But if we were to ask for division, we still aren’t asking for the student to produce a String representation of their Decimal, so the possibility to create these decimals shouldn’t become a problem in the current state of the exercise anyways.

Okay, but then how would current solutions to this exercise be extended to include division?

With the exercise as given, the only way I see of solving it entails using fractions as the backing representation of a Decimal, with BigInts and BigUints as the types for the numerator and denominator respectively. BigUints for the denominator, as the sign need not be stored in more than one place.

If the student is using fractions then, division is very simple to implement: division by p/q becomes simply a multiplication by q/p. Since division in in a sense, fallible (the denominator q should always be non-zero by construction, but the numerator p could be zero, and division by zero is of course undefined), then we have the option of asking the student to return an Option<Decimal> or to return a Decimal and panic on division by zero. The example implementation of the Div trait actually prefers to panic: Div in std::ops - Rust

Closing thoughts

Perhaps we should ask the students to implement division, as not asking to implement it is an artificial constraint over what is otherwise a good exercise in using the type and API they’ve just constructed. I think this is a good opportunity to let them grow a bit more from the Decimal exercise overall.

As an aside, or food for thought: something that’s kind of interesting about the exercise, is that if the solution is implemented through fractions, they need not be in simplest form (ie such that the numerator and denominator are coprimes).

This does mean that the numerator and denominator might skyrocket if the implementer so chooses to allow… which I don’t think is a bad thing. Since making tight fractions isn’t necessarily the point of the exercise.

Though it could be a place for future exploration of bonus tests, perhaps? :D

– Félix

PS: (I’m adding this after having posted) I can implement all of this. I’d be glad to do so :slight_smile: