diff --git a/exercises/practice/raindrops/.approaches/config.json b/exercises/practice/raindrops/.approaches/config.json index a74c828a5..6e437adec 100644 --- a/exercises/practice/raindrops/.approaches/config.json +++ b/exercises/practice/raindrops/.approaches/config.json @@ -22,6 +22,15 @@ "authors": [ "bobahop" ] + }, + { + "uuid": "d16d4056-2434-44ff-aae6-2bd57eb53dd7", + "slug": "modulus", + "title": "Modular Arithmetic", + "blurb": "Use modular arithmetic to generalize.", + "authors": [ + "habere-et-dispertire" + ] } ] } diff --git a/exercises/practice/raindrops/.approaches/introduction.md b/exercises/practice/raindrops/.approaches/introduction.md index 48b7d6b07..bdaa32d91 100644 --- a/exercises/practice/raindrops/.approaches/introduction.md +++ b/exercises/practice/raindrops/.approaches/introduction.md @@ -54,6 +54,32 @@ class RaindropConverter { For more information, check the [`Map` approach][approach-map]. +## Approach: `Modular Arithmetic` + +```java +import java.math.BigInteger; +import static java.math.BigInteger.valueOf; + +class RaindropConverter { + + String convert (int n) { + return switch ( valueOf(n).modPow( valueOf(12), valueOf(105) ).intValue() ) { + case 36 -> "Pling"; + case 85 -> "Plang"; + case 91 -> "Plong"; + case 15 -> "PlingPlang"; + case 21 -> "PlingPlong"; + case 70 -> "PlangPlong"; + case 0 -> "PlingPlangPlong"; + default -> String.valueOf(n); // 1 + }; + } + +} +``` + +For more information, check the [Modular Arithmetic approach][approach-modulus]. + ## Which approach to use? Benchmarking with the [Java Microbenchmark Harness][jmh] is currently outside the scope of this document, @@ -64,4 +90,5 @@ and no other code would need to be added. [remainder-operator]: https://www.geeksforgeeks.org/modulo-or-remainder-operator-in-java/ [approach-if-statements]: https://exercism.org/tracks/java/exercises/raindrops/approaches/if-statements [approach-map]: https://exercism.org/tracks/java/exercises/raindrops/approaches/map +[approach-modulus]: https://exercism.org/tracks/java/exercises/raindrops/approaches/modulus [jmh]: https://github.com/openjdk/jmh diff --git a/exercises/practice/raindrops/.approaches/modulus/content.md b/exercises/practice/raindrops/.approaches/modulus/content.md new file mode 100644 index 000000000..58025ad7b --- /dev/null +++ b/exercises/practice/raindrops/.approaches/modulus/content.md @@ -0,0 +1,31 @@ +# modular arithmetic + +```java +import java.math.BigInteger; +import static java.math.BigInteger.valueOf; + +class RaindropConverter { + + String convert (int n) { + return switch ( valueOf(n).modPow( valueOf(12), valueOf(105) ).intValue() ) { + case 36 -> "Pling"; + case 85 -> "Plang"; + case 91 -> "Plong"; + case 15 -> "PlingPlang"; + case 21 -> "PlingPlong"; + case 70 -> "PlangPlong"; + case 0 -> "PlingPlangPlong"; + default -> String.valueOf(n); // 1 + }; + } + +} +``` + +We can generalize raindrops to any factors if they are [co-prime][co-prime]. +In raindrops the factors 3, 5 and 7 are co-prime (sets of prime numbers are all co-prime) and so we can use [Euler's totient function][euler-totient] to calculate `n¹² mod 105` to give us unique values for the various sounds. +The math behind how we find the right exponent and modulus is explained in an article on the related problem of [Fizz-Buzz][fizz-buzz]. + +[co-prime]: https://en.wikipedia.org/wiki/Coprime_integers +[euler-totient]: https://en.wikipedia.org/wiki/Euler's_totient_function +[fizz-buzz]: https://philcrissman.net/posts/eulers-fizzbuzz/ diff --git a/exercises/practice/raindrops/.approaches/modulus/snippet.txt b/exercises/practice/raindrops/.approaches/modulus/snippet.txt new file mode 100644 index 000000000..7d6ba77f1 --- /dev/null +++ b/exercises/practice/raindrops/.approaches/modulus/snippet.txt @@ -0,0 +1,12 @@ +String convert (int n) { + return switch ( valueOf(n).modPow( valueOf(12), valueOf(105) ).intValue() ) { + case 36 -> "Pling"; + case 85 -> "Plang"; + case 91 -> "Plong"; + case 15 -> "PlingPlang"; + case 21 -> "PlingPlong"; + case 70 -> "PlangPlong"; + case 0 -> "PlingPlangPlong"; + default -> String.valueOf(n); // 1 + }; +}