diff --git a/Doc/Sd1/languageFundamentals.xml b/Doc/Sd1/languageFundamentals.xml index 378a9e470025eec95c30cc1d7b41ff9162c6e326..2191bf3fcad939dabbc5b99e628b8a09594701ea 100644 --- a/Doc/Sd1/languageFundamentals.xml +++ b/Doc/Sd1/languageFundamentals.xml @@ -6238,7 +6238,7 @@ short sum = a + 7; <co linkends="sd1_co_expressionTypeIntToShort-2" xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-C">int</code> operands. The expression <code language="java">4 + 7</code> is thus of type <code language="java">int</code> (not <code - language="java">long</code>). Both operands are static + language="java">short</code>). Both operands are static <abbrev>i.e.</abbrev> their values are known at <emphasis>compile time</emphasis> rather than at <emphasis>run time</emphasis>. The <code language="java">4 + 7</code> @@ -7356,20 +7356,35 @@ age += 200;</programlisting> linkend="sd1_fig_noBinaryPlusByteByte"/> the arithmetic <code language="java">+</code> operator acting any two non-long values will always return a result of type <code - language="java">int</code>. Thus the expression <code - language="java">age + 2</code> of type <code - language="java">int</code> can only be assigned to a variable - <code language="java">age</code> of type <code - language="java">byte</code> when using a cast:</para> + language="java">int</code>. The expression <code + language="java">age + 2</code> is thus of type <code + language="java">int</code> and therefore requires a cast when + being assigned to our variable <code language="java">age</code> + of type <code language="java">byte</code>:</para> <programlisting language="java">byte age = 80; age = (byte)(age + 2);</programlisting> + <note> + <para>Since <code language="java">age</code> is not being + defined as <code language="java">final</code> the value of the + expression <code language="java">age + 2</code> is not being + known at compile time. Adding <code + language="java">final</code> allows for compile time + evaluation and thus assignment to a second variable of type + <code language="java">byte</code> without requiring a + cast:</para> + + <programlisting language="java">final byte age = 80; // Value cannot be altered. + +byte gettingOlder = age + 2; // o.K. without cast: age + 2 can be evaluated at compile time.</programlisting> + </note> + <para>On contrary the operator <code language="java">+=</code> will accept any right hand integer value (even of type <code - language="java">long</code>!) thereby cycling through the range - of byte values e.g.:</para> + language="java">long</code>!) thereby possibly cycling through + the range of byte values e.g.:</para> <informaltable border="1"> <tr> @@ -7387,9 +7402,9 @@ System.out.println("Age:" + age);</programlisting></td> </tr> </informaltable> - <para>Notice 24 being equal to 80 + 200 - 256, the latter being - a <code language="java">byte</code>'s number of different - representable values.</para> + <para>Notice 24 being equal to <code language="java">80 + 200 - + 256</code> with 256 being a <code language="java">byte</code>'s + number of different representable values.</para> </answer> </qandaentry> </qandadiv> @@ -7402,9 +7417,13 @@ System.out.println("Age:" + age);</programlisting></td> <figure xml:id="sd1_fig_OperatorPlusPlus"> <title>Increment operator <code language="java">++</code></title> - <para>Increment variable by 1:</para> + <informaltable border="1"> + <tr> + <th>Increment variable by 1:</th> + + <th>Shorthand version:</th> + </tr> - <informaltable border="0"> <tr> <td valign="top"><programlisting language="none">int a = 4; @@ -7425,6 +7444,69 @@ System.out.println("Value:" + a);</programlisting></td> </informaltable> </figure> + <figure xml:id="sd1_fig_OperatorPlusPlusRangeConsider"> + <title>Different range behaviour!</title> + + <informaltable border="1"> + <tr> + <th>Increment variable by 1:</th> + + <th>Shorthand version:</th> + </tr> + + <tr> + <td valign="top"><programlisting language="none">byte value = 127; // Max possible value + +<emphasis role="red">value = value + 1; // Error: Required type: byte + // Provided:int</emphasis> + +System.out.println(value);</programlisting></td> + + <td valign="top"><programlisting language="none">byte value = 127; // Max possible value + +<emphasis role="red">value++; // o.K., will cycle through range</emphasis> + +System.out.println(value);</programlisting></td> + </tr> + + <tr> + <td><screen>Does not compile</screen></td> + + <td><screen>Value:-128</screen></td> + </tr> + </informaltable> + </figure> + + <figure xml:id="sd1_fig_OperatorPlusPlusRangeCast"> + <title>Cast required</title> + + <informaltable border="1"> + <tr> + <th>Increment variable by 1:</th> + + <th>Shorthand version:</th> + </tr> + + <tr> + <td valign="top"><programlisting language="none">byte value = 127; // Max possible value + +<emphasis role="red">value = (byte)(value + 1); // cast, possible overflow</emphasis> + +System.out.println(value);</programlisting></td> + + <td valign="top"><programlisting language="none">byte value = 127; // Max possible value + +<emphasis role="red">value++; // o.K., will cycle through range</emphasis> + +System.out.println(value);</programlisting></td> + </tr> + + <tr> + <td colspan="2"><screen>Value:-128</screen></td> + </tr> + </informaltable> + </figure> + <figure xml:id="sd1_fig_OperatorPlusPlusPostfixPrefix"> <title>Prefix and postfix notation</title> diff --git a/Doc/Sd1/statements.xml b/Doc/Sd1/statements.xml index 07524b8767dde20d7b31ee161174f5a8f83ac0c2..b3035a4e5d2f856cfdcb50f0f5fd727a3d43f67a 100644 --- a/Doc/Sd1/statements.xml +++ b/Doc/Sd1/statements.xml @@ -4100,48 +4100,79 @@ System.out.format("Start:<emphasis role="red">%5d</emphasis>:End", <emphasis 10| 10 20 30 40 50 60 70 80 90 100</screen> <para>The number of rows and columns are equal. Provide an - appropriate parameter <code language="java">final int LIMIT = - ...</code> so that your implementation works for different - values just by changing its value.</para> + appropriate parameter i.e <code language="java">final int SIZE + = 12</code> allowing for a configurable number of + columns.</para> <tip> - <para>You'll need an inner loop nested within an outer one - creating rows and columns like:</para> + <orderedlist> + <listitem> + <para>You'll need an inner loop nested within an outer + one creating rows and columns like:</para> - <programlisting language="java">for (int row = 0; ...){ + <programlisting language="none">for (int row = 1; ...){ - for (int col = 0; ... ) { - ... + for (int col = 1; ... ) { + ... // Using System.out.print(...) rather than ...print<emphasis + role="red">ln</emphasis>() avoiding line breaks. } + System.out.println(); // Adding a newline after each set of values }</programlisting> - </tip> - </question> + </listitem> - <answer> - <programlisting language="java">public static void main(String[] args) { + <listitem> + <para>Having integer values of differing lengths you + have to consider right justified output. The integer + <link + xlink:href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Formatter.html#syntax">format + specifier</link> <code>%...d</code> is your friend here. + The subsequent example prints four integer values in + right justified style within output fields of common + length 5 irrespective of differing lengths:</para> - final int LIMIT = 10; // Parameter is subject to change. + <informaltable border="1"> + <tr> + <th>Code</th> - System.out.print(" * | "); + <th>Output</th> + </tr> - for (int col = 1; col <= LIMIT; col++) { // Header line of columns ranging - System.out.format("%3d ", col); // from 1 to LIMIT. - } - System.out.println(); + <tr> + <td valign="top"><programlisting language="java">System.out.format("|%5d|%5d|%5d|%5d|", 1, 100, 1000, 10000);</programlisting></td> - System.out.print("---+"); // Header / table body separator. - for (int col = 1; col <= LIMIT; col++) { - System.out.print("-----"); - } - System.out.println(); + <td valign="top"><screen>| 1| 100| 1000|10000|</screen></td> + </tr> + </informaltable> + + <para>The %...s format specifier may be used for strings + accordingly.</para> + </listitem> + </orderedlist> + </tip> + </question> - for (int row = 1; row <= LIMIT; row++) { // Printing rows. - System.out.format("%3d| ", row); - for (int col = 1; col <= LIMIT; col++) { // Printing columns. - System.out.format("%3d ", row * col); + <answer> + <programlisting language="java">// Block 1: Configuration parameter +// +final int SIZE = 6; // Table size is subject to change. + +// Block 2: Printing table's head +// +System.out.print(" * | "); // Printing table head's first line +for (int col = 1; col <= SIZE; col++) { // using column values ranging from 1 to SIZE: + System.out.format("%3d ", col); // * | 1 2 3 ... +} +System.out.print("\n---+" + // Printing table head's second line + "-----".repeat(SIZE) ); // ---+--------------- ... + +// Block 3: Printing table's content +// organized in rows and columns. +// +for (int row = 1; row <= SIZE; row++) { // Printing rows. + System.out.format("\n%3d| ", row); // Printing new line by \n and beginning of row e.g. " 5|" + for (int col = 1; col <= SIZE; col++) { + System.out.format("%3d ", row * col); // Printing row times column product values. } - System.out.println(); - } }</programlisting> </answer> </qandaentry> @@ -4173,32 +4204,59 @@ System.out.format("Start:<emphasis role="red">%5d</emphasis>:End", <emphasis </question> <answer> - <para>We have to move the header to the table's bottom. Apart - from that the required change with respect to your previous - exercise is tiny: The <quote>inner</quote> loop must end when - reaching the current row's index:</para> + <para>We need two changes with respect to the <link + linkend="sd1QandaIntermediateMultiplyTable1">previous + exercise</link>:</para> - <programlisting language="java">final int LIMIT = 10; // Parameter is subject to change. + <orderedlist> + <listitem> + <para>The number of columns to be printed has to be + limited depending on which row we currently print. We thus + replace</para> -for (int row = 1; row <= LIMIT; row++) { // Printing rows. - System.out.format("%3d| ", row); + <programlisting language="none">for (int col = 1; col <= <emphasis + role="red">SIZE</emphasis>; col++) { // Printing columns.</programlisting> - for (int col = 1; <emphasis role="bold">col <= row;</emphasis> col++) { // Printing column values until row index only. - System.out.format("%3d ", row * col); - } - System.out.println(); + <para>by</para> + + <programlisting language="none">for (int col = 1; col <= <emphasis + role="red">row</emphasis>; col++) { // Printing columns depending on current row value.</programlisting> + </listitem> + + <listitem> + <para>Having a table tail now rather than a head we defer + our former solution's second block to the end thereby + reversing its internal order of print statements. The + following code also includes some minor newline character + fiddling:</para> + + <programlisting language="java">// Block 1: Configuration parameter +// +final int SIZE = 10; // Table size is subject to change. + +// Block 2: Printing table's content +// organized in rows and columns. +// +for (int row = 1; row <= SIZE; row++) { // Printing rows. + System.out.format("%3d| ", row); // Printing new line by \n and beginning of row e.g. " 5|" + for (int col = 1; col <= SIZE; col++) { + System.out.format("%3d ", row * col); // Printing row times column product values. + } + System.out.println(); // New line after printing row. } -System.out.print("---+"); // Header / table body separator. - for (int col = 1; col <= LIMIT; col++) { - System.out.print("-----"); - } - System.out.println(); - System.out.print(" * | "); - for (int col = 1; col <= LIMIT; col++) { // Header line of columns ranging - System.out.format("%3d ", col); // from 1 to LIMIT. - } -System.out.println();</programlisting> +// Block 3: Printing table's tail. +// +System.out.print("---+" + // Printing table tail's first line + "-----".repeat(SIZE) + // ---+--------------- ... + '\n'); // being finished by a newline character. + +System.out.print(" * | "); // Printing table tail's second line +for (int col = 1; col <= SIZE; col++) { // using column values ranging from 1 to SIZE: + System.out.format("%3d ", col); // * | 1 2 3 ... +}</programlisting> + </listitem> + </orderedlist> </answer> </qandaentry> </qandadiv> @@ -6250,7 +6308,7 @@ for (int i = 0; <emphasis role="red">!numberWasFound &&</emphasis> i < <section xml:id="sw1SectionPythagoreanTriples"> <title>Pythagorean triples</title> - <qandaset defaultlabel="qanda" xml:id="sw1QandaPythagoreanTriples"> + <qandaset defaultlabel="qanda" xml:id="sw1QandaPythagoreanTriples1"> <qandadiv> <qandaentry> <question> @@ -6267,7 +6325,107 @@ for (int i = 0; <emphasis role="red">!numberWasFound &&</emphasis> i < </imageobject> </mediaobject> - <para>For most value combinations at least one value will be + <para>Some integer triples do exist e.g.:</para> + + <itemizedlist> + <listitem> + <informalequation> + <m:math display="block"> + <m:mrow> + <m:mrow> + <m:msup> + <m:mi>3</m:mi> + + <m:mi>2</m:mi> + </m:msup> + + <m:mo>+</m:mo> + + <m:msup> + <m:mi>4</m:mi> + + <m:mi>2</m:mi> + </m:msup> + </m:mrow> + + <m:mo>=</m:mo> + + <m:msup> + <m:mi>5</m:mi> + + <m:mi>2</m:mi> + </m:msup> + </m:mrow> + </m:math> + </informalequation> + </listitem> + + <listitem> + <informalequation> + <m:math display="block"> + <m:mrow> + <m:mrow> + <m:msup> + <m:mi>6</m:mi> + + <m:mi>2</m:mi> + </m:msup> + + <m:mo>+</m:mo> + + <m:msup> + <m:mi>8</m:mi> + + <m:mi>2</m:mi> + </m:msup> + </m:mrow> + + <m:mo>=</m:mo> + + <m:msup> + <m:mi>10</m:mi> + + <m:mi>2</m:mi> + </m:msup> + </m:mrow> + </m:math> + </informalequation> + </listitem> + + <listitem> + <informalequation> + <m:math display="block"> + <m:mrow> + <m:mrow> + <m:msup> + <m:mi>5</m:mi> + + <m:mi>2</m:mi> + </m:msup> + + <m:mo>+</m:mo> + + <m:msup> + <m:mi>12</m:mi> + + <m:mi>2</m:mi> + </m:msup> + </m:mrow> + + <m:mo>=</m:mo> + + <m:msup> + <m:mi>13</m:mi> + + <m:mi>2</m:mi> + </m:msup> + </m:mrow> + </m:math> + </informalequation> + </listitem> + </itemizedlist> + + <para>For most combinations however at least one value will be of real rather than of integer value e.g.:</para> <itemizedlist> @@ -6358,28 +6516,8 @@ for (int i = 0; <emphasis role="red">!numberWasFound &&</emphasis> i < <m:mo>)</m:mo> </m:mrow> </m:math> - </inlineequation> of non-zero integer values which - simultaneously obey the additional constraint <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:mi>a</m:mi> - - <m:mo>+</m:mo> - - <m:mi>b</m:mi> - - <m:mo>+</m:mo> - - <m:mi>c</m:mi> - </m:mrow> - - <m:mo>=</m:mo> - - <m:mn>840</m:mn> - </m:mrow> - </m:math> - </inlineequation>.</para> + </inlineequation> of non-zero integer values being smaller + than 100 each. Keep the limit of 100 flexible.</para> <tip> <para>Think of creating all possible triples <inlineequation> @@ -6419,7 +6557,7 @@ for (int i = 0; <emphasis role="red">!numberWasFound &&</emphasis> i < <td>1</td> - <td>1</td> + <td>2</td> </tr> <tr> @@ -6427,7 +6565,7 @@ for (int i = 0; <emphasis role="red">!numberWasFound &&</emphasis> i < <td>1</td> - <td>1</td> + <td>2</td> </tr> <tr> @@ -6439,766 +6577,336 @@ for (int i = 0; <emphasis role="red">!numberWasFound &&</emphasis> i < </tr> <tr> - <td>838</td> + <td>99</td> - <td>838</td> + <td>99</td> - <td>838</td> + <td>100</td> </tr> </informaltable> - <para>Why does an upper value of 838 rather then the - proposed sum value of 840 appears here?</para> + <para>Why does an upper value of 99 appears here for a and + b? Why do we have a lower bond of 2 for the variable + c?</para> + </tip> - <para>This list mostly contains values like <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mo>(</m:mo> + <tip> + <para>Consider using three nested loops for creating all + possible combinations. Do not yet bother about possible + duplicates. Your result output may look like:</para> + + <screen>Found (4, 3, 5) +Found (3, 4, 5) +Found (8, 6, 10) +Found (6, 8, 10) +...</screen> + </tip> + </question> - <m:mrow> - <m:mn>1</m:mn> + <answer> + <para>A value of e.g. b == 100 would imply a == 0 + contradicting the description. Likewise c == 1 wouls imply + either a == 0 or b == 0;</para> - <m:mo>,</m:mo> + <para>We create all possible combinations by using three + nested loops and filtering for the desired results: </para> - <m:mn>3</m:mn> + <programlisting language="java">final int LIMIT = 100; - <m:mo>,</m:mo> +for (int c = 1; c <= LIMIT; c++) { + for (int b = 1; b < LIMIT; b++) { + for (int a = 1; a < LIMIT; a++) { + if (a * a + b * b == c * c ) { // Limit output by filtering for pythagorean triples; + System.out.println("Found (" + a + ", " + + "" + b + ", " + c + ")"); + } + } + } +}</programlisting> - <m:mn>4</m:mn> - </m:mrow> + <para>This results in:</para> - <m:mo>)</m:mo> - </m:mrow> - </m:math> - </inlineequation> failing both our restrictions - <inlineequation> - <m:math display="inline"> - <m:mrow> + <screen>Found (4, 3, 5) +Found (3, 4, 5) +Found (8, 6, 10) +Found (6, 8, 10) +Found (12, 5, 13) +... +Found (96, 28, 100) +Found (80, 60, 100) +Found (60, 80, 100) +Found (28, 96, 100)</screen> + + <para>Note duplicates like <code>(4, 3, 5)</code> and + <code>(3, 4, 5)</code> being present in the above list</para> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + + <qandaset defaultlabel="qanda" + xml:id="sw1QandaPythagoreanTriplesNoDuplicates"> + <title>Avoiding duplicates and gaining performance</title> + + <qandadiv> + <qandaentry> + <question> + <para>There are several issues with the previous + solution:</para> + + <orderedlist> + <listitem> + <para>It creates a great number of combinations like + <inlineequation> + <m:math display="inline"> <m:mrow> - <m:msup> - <m:mn>1</m:mn> + <m:mo>(</m:mo> - <m:mn>2</m:mn> - </m:msup> + <m:mrow> + <m:mn>4</m:mn> - <m:mo>+</m:mo> + <m:mo>,</m:mo> - <m:msup> - <m:mn>3</m:mn> + <m:mn>4</m:mn> - <m:mn>2</m:mn> - </m:msup> - </m:mrow> + <m:mo>,</m:mo> + + <m:mn>5</m:mn> + </m:mrow> - <m:mo>≠</m:mo> + <m:mo>)</m:mo> + </m:mrow> + </m:math> + </inlineequation> which could be easily ruled out + beforehand rather then creating and filtering them.</para> + <para>The former solution filters <inlineequation> + <m:math display="inline"> <m:msup> - <m:mn>4</m:mn> + <m:mi>99</m:mi> - <m:mn>2</m:mn> + <m:mi>3</m:mi> </m:msup> - </m:mrow> - </m:math> - </inlineequation> and <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:mn>1</m:mn> + </m:math> + </inlineequation>combinations or roughly one + million.</para> + </listitem> - <m:mo>+</m:mo> + <listitem> + <para>Triples having identical values of <code>a</code> + and <code>b</code> in different order like <code>(3, 4, + 5)</code> and <code>(4, 3, 5)</code> are equivalent. For + this reason we look for ordered triples only.</para> + </listitem> + </orderedlist> + + <para>The problem can thus be restated to find the set of all + triples <inlineequation> + <m:math display="inline"> + <m:mrow> + <m:mo>(</m:mo> - <m:mn>3</m:mn> + <m:mrow> + <m:mi>a</m:mi> - <m:mo>+</m:mo> + <m:mo>,</m:mo> - <m:mn>4</m:mn> - </m:mrow> + <m:mi>b</m:mi> - <m:mo>≠</m:mo> + <m:mo>,</m:mo> - <m:mi>840</m:mi> + <m:mi>c</m:mi> </m:mrow> - </m:math> - </inlineequation>. These triples have thus to be filtered - retaining only the desired combinations simultaneously - obeying both <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:msup> - <m:mi>a</m:mi> - - <m:mn>2</m:mn> - </m:msup> - <m:mo>+</m:mo> + <m:mo>)</m:mo> - <m:msup> - <m:mi>b</m:mi> + <m:mo>∈</m:mo> - <m:mn>2</m:mn> - </m:msup> - </m:mrow> - - <m:mo>=</m:mo> - - <m:msup> - <m:mi>c</m:mi> - - <m:mn>2</m:mn> - </m:msup> - </m:mrow> - </m:math> - </inlineequation> and <inlineequation> - <m:math display="inline"> <m:mrow> - <m:mrow> - <m:mi>a</m:mi> - - <m:mo>+</m:mo> - - <m:mi>b</m:mi> - - <m:mo>+</m:mo> - - <m:mi>c</m:mi> - </m:mrow> - - <m:mo>=</m:mo> - - <m:mi>840</m:mi> - </m:mrow> - </m:math> - </inlineequation>. This might be accomplished by - implementing three nested loops:</para> - - <programlisting language="java">for (int a = 1; a <= 838; a++) { - for (int b = 1; b <= 838; b++) { - for (int c = 1; c <= 838; c++) { - if (a*a + b*b == c*c && // Pythagorean condition - a + b + c == 840) { // sum constraint - System.out.println(" Found (" + a + ", " + b + ", " + c + ")"); - } - } - } -}</programlisting> - - <para>The above code generating <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:mn>838</m:mn> - - <m:mo>×</m:mo> - - <m:mn>838</m:mn> - - <m:mo>×</m:mo> - - <m:mn>838</m:mn> - </m:mrow> - - <m:mo>=</m:mo> - - <m:mn>588480472</m:mn> - </m:mrow> - </m:math> - </inlineequation> combinations will run quite some time! - Thus we are looking for a better (more efficient) - solution.</para> - - <para>There are several issues with the above code:</para> - - <orderedlist> - <listitem> - <para>It creates a great number of combinations like - <inlineequation> - <m:math display="inline"> + <m:msup> <m:mrow> - <m:mo>(</m:mo> + <m:mo>[</m:mo> <m:mrow> <m:mn>1</m:mn> <m:mo>,</m:mo> - <m:mn>4</m:mn> - - <m:mo>,</m:mo> - - <m:mn>3</m:mn> + <m:mi>LIMIT</m:mi> </m:mrow> - <m:mo>)</m:mo> + <m:mo>]</m:mo> </m:mrow> - </m:math> - </inlineequation> which could be easily ruled out - beforehand rather then creating and filtering - them.</para> - - <para>Do we really need three nested loops?</para> - </listitem> - - <listitem> - <para>Triples having identical values in different order - like <code>(40, 399, 401)</code> and <code>(40, 401, - 399)</code> are equivalent. For this reason we may - consider only triples being ordered by value.</para> - </listitem> - </orderedlist> - <para>The problem can thus be stated to find the set of all - triples <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mo>(</m:mo> + <m:mi>3</m:mi> + </m:msup> + </m:mrow> + </m:mrow> + </m:math> + </inlineequation> simultaneously obeying:</para> + <orderedlist> + <listitem xml:id="sw1PhytagoreanTripletCondition1"> + <para><inlineequation> + <m:math display="inline"> <m:mrow> <m:mi>a</m:mi> - <m:mo>,</m:mo> + <m:mo>≤</m:mo> <m:mi>b</m:mi> - <m:mo>,</m:mo> + <m:mo><</m:mo> <m:mi>c</m:mi> </m:mrow> + </m:math> + </inlineequation></para> + </listitem> - <m:mo>)</m:mo> - - <m:mo>∈</m:mo> - + <listitem> + <para><inlineequation> + <m:math display="inline"> <m:mrow> - <m:msup> - <m:mrow> - <m:mo>[</m:mo> - - <m:mrow> - <m:mn>1</m:mn> - - <m:mo>,</m:mo> - - <m:mi>838</m:mi> - </m:mrow> - - <m:mo>]</m:mo> - </m:mrow> - - <m:mi>3</m:mi> - </m:msup> - </m:mrow> - </m:mrow> - </m:math> - </inlineequation> simultaneously obeying:</para> - - <orderedlist> - <listitem xml:id="sw1PhytagoreanTripletCondition1"> - <para><inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mi>a</m:mi> - - <m:mo>≤</m:mo> - - <m:mi>b</m:mi> - - <m:mo>≤</m:mo> - - <m:mi>c</m:mi> - </m:mrow> - </m:math> - </inlineequation></para> - </listitem> - - <listitem xml:id="sw1PhytagoreanTripletCondition2"> - <para><inlineequation> - <m:math display="inline"> <m:mrow> - <m:mrow> + <m:msup> <m:mi>a</m:mi> - <m:mo>+</m:mo> - - <m:mi>b</m:mi> - - <m:mo>+</m:mo> - - <m:mi>c</m:mi> - </m:mrow> - - <m:mo>=</m:mo> - - <m:mn>840</m:mn> - </m:mrow> - </m:math> - </inlineequation></para> - </listitem> - - <listitem> - <para><inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:msup> - <m:mi>a</m:mi> - - <m:mn>2</m:mn> - </m:msup> - - <m:mo>+</m:mo> - - <m:msup> - <m:mi>b</m:mi> - - <m:mn>2</m:mn> - </m:msup> - </m:mrow> + <m:mn>2</m:mn> + </m:msup> - <m:mo>=</m:mo> + <m:mo>+</m:mo> <m:msup> - <m:mi>c</m:mi> + <m:mi>b</m:mi> <m:mn>2</m:mn> </m:msup> </m:mrow> - </m:math> - </inlineequation></para> - </listitem> - </orderedlist> - - <para>Find a better way than the above three nested - loops.</para> - </tip> - </question> - - <answer> - <para>Since each variable value must be greater than zero the - maximum possible value is 840 - 1 - 1 = 838.</para> - - <para>The <quote>last</quote> triple obeying both restrictions - <xref linkend="sw1PhytagoreanTripletCondition1"/> and <xref - linkend="sw1PhytagoreanTripletCondition2"/> is (280, 280, - 280). Due to the restriction <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:mi>a</m:mi> - - <m:mo>+</m:mo> - - <m:mi>b</m:mi> - - <m:mo>+</m:mo> - - <m:mi>c</m:mi> - </m:mrow> - - <m:mo>=</m:mo> - - <m:mi>840</m:mi> - </m:mrow> - </m:math> - </inlineequation> two variable values already determine the - third one: For a given value of variable a from the outer - <code language="java">for</code> loop any value of b will - imply <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mi>c</m:mi> - - <m:mo>=</m:mo> - - <m:mrow> - <m:mn>840</m:mn> - - <m:mo>-</m:mo> - - <m:mi>a</m:mi> - - <m:mo>-</m:mo> - - <m:mi>b</m:mi> - </m:mrow> - </m:mrow> - </m:math> - </inlineequation>.</para> - - <para>We thus only need two nested loops for generating all - possible triples: If the value of b is being incremented by 1 - then c has to be decremented by 1 as well and is thus - completely determined.</para> - - <para>For convenience reasons we introduce a variable <code - language="java">int sum = 840</code> representing our sum of - all three values. Our filter condition now only needs to check - for the remaining Pythagorean condition <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:msup> - <m:mi>a</m:mi> - - <m:mn>2</m:mn> - </m:msup> - - <m:mo>+</m:mo> - <m:msup> - <m:mi>b</m:mi> - - <m:mn>2</m:mn> - </m:msup> - </m:mrow> - - <m:mo>=</m:mo> - - <m:msup> - <m:mi>c</m:mi> - - <m:mn>2</m:mn> - </m:msup> - </m:mrow> - </m:math> - </inlineequation>:</para> - - <programlisting language="java">final int sum = 840; - -for (int a = 1; a <= sum / 3; a++) { - - final int aSquare = a * a; // Calculate square of variable a - // outside subsequent loop. - - for (int b = a, c = sum - a - b; b < c; b++, c--) { - - if (aSquare + b * b == c * c) { // Filter for pythagorean triples - System.out.println("(" + a + ", " + b + ", " + c + ")"); - } - } -}</programlisting> - - <para>We've reduced the original code from three to just two - nested loops. Running this code reveals eight triples:</para> - - <screen>(40, 399, 401) -(56, 390, 394) -(105, 360, 375) -(120, 350, 370) -(140, 336, 364) -(168, 315, 357) -(210, 280, 350) -(240, 252, 348)</screen> - - <para>The above code can be simplified even further. We - introduce a variable s being shorthand for <code - language="java">sum</code>. The <quote>inner</quote> <code - language="java">for</code> loop so far starts with a value of - <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mi>b</m:mi> - - <m:mo>=</m:mo> - - <m:mi>a</m:mi> - </m:mrow> - </m:math> - </inlineequation> and thus <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mi>c</m:mi> - - <m:mo>=</m:mo> - - <m:mrow> - <m:mi>s</m:mi> - - <m:mo>-</m:mo> - - <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - - <m:mi>a</m:mi> - </m:mrow> - </m:mrow> - </m:mrow> - </m:math> - </inlineequation>. Then during each step <code - language="java">b</code> is being incremented by 1 and <code - language="java">c</code> will be decremented by the same - amount.</para> - - <para>Regarding the n-th step of the inner loop we thus look - for a value of n so that the following equation becomes - true:</para> - - <informalequation> - <m:math display="inline"> - <m:mrow> - <m:mrow> - <m:msup> - <m:mi>a</m:mi> - - <m:mi>2</m:mi> - </m:msup> - - <m:mo>+</m:mo> - - <m:munder accentunder="true"> - <m:msup> - <m:mrow> - <m:mo>(</m:mo> - - <m:mrow> - <m:mi>a</m:mi> - - <m:mo>+</m:mo> - - <m:mi>n</m:mi> - </m:mrow> - - <m:mo>)</m:mo> - </m:mrow> - - <m:mi>2</m:mi> - </m:msup> - - <m:munder accentunder="true"> - <m:mo stretchy="true">︸</m:mo> + <m:mo>=</m:mo> <m:msup> - <m:mi>b</m:mi> + <m:mi>c</m:mi> - <m:mi>2</m:mi> + <m:mn>2</m:mn> </m:msup> - </m:munder> - </m:munder> - </m:mrow> - - <m:mo>=</m:mo> - - <m:munder> - <m:msup> - <m:mrow> - <m:mo>(</m:mo> - - <m:mrow> - <m:mi>s</m:mi> - - <m:mo>-</m:mo> - - <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - - <m:mi>a</m:mi> - </m:mrow> - - <m:mo>-</m:mo> - - <m:mi>n</m:mi> - </m:mrow> - - <m:mo>)</m:mo> </m:mrow> + </m:math> + </inlineequation></para> + </listitem> + </orderedlist> - <m:mi>2</m:mi> - </m:msup> - - <m:munder> - <m:mo stretchy="true">︸</m:mo> - - <m:msup> - <m:mi>c</m:mi> - - <m:mi>2</m:mi> - </m:msup> - </m:munder> - </m:munder> - </m:mrow> - </m:math> - </informalequation> - - <!-- - <informalequation> - <mathphrase>$a^2 + \underbrace{(a + n)^2}_{b^2} = - \underbrace{(s - 2a -n)^2}_{c^2}$</mathphrase> - </informalequation> - --> + <para>Your solution shall account for both the number of + combinations being evaluated and the number of Pythagorean + triples being found creating a final line like:</para> - <para>Solving this equation for n results in:</para> + <screen>52 triples found by filtering 131935 combinations</screen> - <informalequation> - <m:math display="inline"> - <m:mrow> - <m:mi>n</m:mi> + <para>Your solution should find all 52 triples by filtering + from at most 131935 combinations. If you do need less + combinations in the first place please let me know. I'm more + than happy publishing an enhanced solution.</para> + </question> - <m:mo>=</m:mo> + <answer> + <para>Based on our previous solution we introduce the + following changes:</para> - <m:mfrac> - <m:mrow> + <orderedlist> + <listitem> + <para>We calculate <inlineequation> + <m:math display="inline"> <m:msup> - <m:mrow> - <m:mo>(</m:mo> - - <m:mrow> - <m:mi>s</m:mi> - - <m:mo>-</m:mo> - - <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - - <m:mi>a</m:mi> - </m:mrow> - </m:mrow> - - <m:mo>)</m:mo> - </m:mrow> + <m:mi>c</m:mi> <m:mi>2</m:mi> </m:msup> + </m:math> + </inlineequation> beforehand:</para> - <m:mo>-</m:mo> + <programlisting language="java">... +for (int c = 2; c <= LIMIT; c++) { + <emphasis role="red">final int cSquare = c * c</emphasis>; +...</programlisting> + </listitem> + <listitem> + <para>Within the next inner loop we calculate + <inlineequation> + <m:math display="inline"> <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - <m:msup> - <m:mi>a</m:mi> + <m:mi>c</m:mi> <m:mi>2</m:mi> </m:msup> - </m:mrow> - </m:mrow> - - <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - - <m:mrow> - <m:mo>(</m:mo> - - <m:mrow> - <m:mi>s</m:mi> - - <m:mo>-</m:mo> - - <m:mi>a</m:mi> - </m:mrow> - - <m:mo>)</m:mo> - </m:mrow> - </m:mrow> - </m:mfrac> - </m:mrow> - </m:math> - </informalequation> - - <para>So for each given value of a there is either no or - exactly one possible solution (since <code - language="java">n</code> is of integer type). This way the - <quote>inner</quote> loop becomes obsolete.</para> - - <para>The above equation must hold for integer arithmetic - leaving no fractional remainder. We introduce two variables - <code language="java">numerator</code> and <code - language="java">denominator</code> representing the above - terms <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:msup> - <m:mrow> - <m:mo>(</m:mo> - - <m:mrow> - <m:mi>s</m:mi> - - <m:mo>-</m:mo> - - <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - - <m:mi>a</m:mi> - </m:mrow> - </m:mrow> - - <m:mo>)</m:mo> - </m:mrow> - - <m:mi>2</m:mi> - </m:msup> - - <m:mo>-</m:mo> - - <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - - <m:msup> - <m:mi>a</m:mi> - - <m:mi>2</m:mi> - </m:msup> - </m:mrow> - </m:mrow> - </m:math> - </inlineequation> and <inlineequation> - <m:math display="inline"> - <m:mrow> - <m:mn>2</m:mn> - - <m:mo>â¢</m:mo> - - <m:mrow> - <m:mo>(</m:mo> - - <m:mrow> - <m:mi>s</m:mi> <m:mo>-</m:mo> - <m:mi>a</m:mi> - </m:mrow> + <m:msup> + <m:mi>b</m:mi> - <m:mo>)</m:mo> - </m:mrow> - </m:mrow> - </m:math> - </inlineequation>. The <quote>remainder of modulus</quote> - operator <code language="java">%</code> testing for a zero - remainder filters the desired triples:</para> + <m:mi>2</m:mi> + </m:msup> + </m:mrow> + </m:math> + </inlineequation> beforehand as well:</para> - <programlisting language="java">final int sum = 840; + <programlisting language="java">... +for (int b = 1; b < c; b++) { // b must not exceed c since a == 0 otherwise + <emphasis role="red">final int cSquare_minus_bSquare = cSquare - b * b</emphasis>; +...</programlisting> + </listitem> -for (int a = 1; a <= sum / 3; a++) { + <listitem> + <para>The innermost loop will terminate on two + conditions:</para> + + <programlisting language="java">... +for (int a = 1; + <emphasis role="red">a <= b</emphasis> && // Only ordered triples + <emphasis role="red">a * a <= cSquare_minus_bSquare</emphasis>; // Only till square root of c² - b² + a++) { ...</programlisting> + </listitem> - final int numerator = (sum - 2 * a) * (sum - 2 * a) - 2 * a * a, - denominator = 2 * (sum - a); + <listitem> + <para>Finally we re-write our filtering condition:</para> - final int remainder = numerator % denominator; - if (0 == remainder) { - final int n = numerator / denominator; - System.out.println("(" + a + ", " + (a + n) + ", " + (sum - 2 * a - n) + ")"); - } + <programlisting language="java">... +if (<emphasis role="red">a * a == cSquare_minus_bSquare</emphasis>) { // Equivalent to a² + b² == c² + System.out.println("Found (" + a + ", " + b + ", " + c + ")"); }</programlisting> + </listitem> + </orderedlist> - <para>We've thus reduced three nested loops into just one - getting exactly the same result as before. Obviously execution - is (again) ways faster paying off when looking for larger - values of <code language="java">sum</code>.</para> + <para>Piecing together these snippets and adding two variables + <code language="java">comparisons</code> and <code + language="java">countTriples</code> for accounting yields our + final solution:</para> + + <programlisting language="java">final int LIMIT = 100; + +int comparisons = 0, countTriples = 0; + +for (int c = 2; c <= LIMIT; c++) { + final int cSquare = c * c; + for (int b = 1; b < c; b++) { // b must not exceed c since a == 0 otherwise + final int cSquare_minus_bSquare = cSquare - b * b; // c² - b² + for (int a = 1; + a <= b && // Only ordered triples + a * a <= cSquare_minus_bSquare; // Only till square root of c² - b² + a++) { + if (a * a == cSquare_minus_bSquare ) { // Equivalent to a² + b² == c² + System.out.println( + "Found (" + a + ", " + b + ", " + c + ")"); + countTriples++; + } + comparisons++; + } + } +} +System.out.println(countTriples + " triples found by filtering " + comparisons + " combinations");</programlisting> </answer> </qandaentry> </qandadiv>