<?xml version="1.0" encoding="UTF-8"?>
<section version="5.0" xml:id="sd1_exam_2021_winter" xml:lang="en"
         xmlns="http://docbook.org/ns/docbook"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xmlns:xila="http://www.w3.org/2001/XInclude/local-attributes"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         xmlns:trans="http://docbook.org/ns/transclusion"
         xmlns:svg="http://www.w3.org/2000/svg"
         xmlns:m="http://www.w3.org/1998/Math/MathML"
         xmlns:html="http://www.w3.org/1999/xhtml"
         xmlns:db="http://docbook.org/ns/docbook">
  <title>SD1 examination winter 2021</title>

  <section xml:id="sd1_exam_2021_winter_task1">
    <title>Implementing tasks</title>

    <section xml:id="sd1_exam_2021_winter_task1_preparation">
      <title>Preparation</title>

      <orderedlist>
        <listitem>
          <para>Download and unzip the above file
          <filename>exam.zip</filename>. You should see a directory
          »<filename>Exam</filename>« containing a
          <filename>pom.xml</filename> file.</para>
        </listitem>

        <listitem>
          <para>Open this project in your <productname>IDEA</productname> IDE
          by selecting the <filename>Exam/pom.xml</filename> file.</para>
        </listitem>
      </orderedlist>
    </section>

    <section xml:id="sd1_exam_2021_winter_task1_tasks">
      <title>Tasks</title>

      <qandaset defaultlabel="qanda" xml:id="sd1_exam_2021_winter_task1Qanda">
        <qandadiv>
          <qandaentry>
            <question>
              <para>Open the <filename>Readme.md</filename> file in your
              project's root. It contains all necessary instructions for
              solving the implementation tasks.</para>
            </question>

            <answer>
              <para>Solution see <link
              xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/-/tree/master/Klausuren/Sd1/2021winter/Solve">winter
              2021 Exam</link>.</para>
            </answer>
          </qandaentry>
        </qandadiv>
      </qandaset>
    </section>

    <section xml:id="sd1_exam_2021_winter_examCaveats">
      <title>Caveats</title>

      <itemizedlist>
        <listitem>
          <para>When approaching end of examination check your input for
          completeness prior to being automatically logged out by the system.
          Remember: There is 120 minutes for the examination and another 5
          minutes to check for completeness.</para>
        </listitem>

        <listitem>
          <para>Projects residing just on your local workstation's file system
          cannot be recovered after finishing the exam.</para>
        </listitem>
      </itemizedlist>
    </section>
  </section>

  <section xml:id="sd1_exam_2021_winter_task2">
    <title><methodname>equals()</methodname> and
    <methodname>hashCode()</methodname></title>

    <qandaset defaultlabel="qanda" xml:id="sd1_exam_2021_winter_task2Qanda">
      <qandadiv>
        <qandaentry>
          <question>
            <para>Consider the following <classname>Person</classname>
            class:</para>

            <programlisting language="java">public class Person {

    private String name, // Guaranteed never
            comment;     // to be null

    private  int ageInYears;

    // Other methods omitted for brevity

    @Override public boolean equals(Object o) {
        if (o instanceof  Person) {
            final Person p = (Person) o;
            return ageInYears == p.ageInYears &amp;&amp;
                    name.equals(p.name);
        } else {
            return false;
        }
    }

    @Override public int hashCode() {
        return ageInYears + 13 * comment.hashCode();
    }
}</programlisting>

            <para>We assume the above <methodname>equals()</methodname>
            implementation to be correct. Answer the following two
            questions:</para>

            <orderedlist>
              <listitem>
                <para>Is this implementation correct regarding the <link
                xlink:href="https://freedocs.mi.hdm-stuttgart.de/doc/openjdk-21-doc/api/java.base/java/lang/Object.html#hashCode()">contract
                between <methodname>equals()</methodname> and
                <methodname>hashCode()</methodname></link>? Correct if
                necessary.</para>
              </listitem>

              <listitem>
                <para>After correcting possible flaws: Is the resulting
                implementation »good« with respect to distinguishing objects?
                Amend if possible.</para>
              </listitem>
            </orderedlist>

            <para>Explain your answers.</para>
          </question>

          <answer>
            <orderedlist>
              <listitem>
                <para>The <methodname>equals(...)</methodname> method defines
                two <classname>Person</classname> instances to be equal when
                having common age and Name. Thus two instances e.g. <code>(18,
                "Eve Porter", "New Friend from holiday")</code> and <code>(18,
                "Eve Porter", "Friendly person")</code>of common name and age
                but having a different comment will still considered to be
                equal.</para>

                <para>Since equality is being defined solely on
                <property>age</property> and <property>name</property> the
                <property>comment</property> attribute must not be used for
                implementing <methodname>hashCode()</methodname>. Otherwise
                the above example will result in different hash values
                contradicting the <methodname>equals(...)</methodname> /
                <methodname>hashCode()</methodname> contract. We thus
                have:</para>

                <programlisting language="java">public class Person {
  ...
    @Override public int hashCode() {
        return ageInYears;
    }
}</programlisting>
              </listitem>

              <listitem>
                <para>The previously corrected
                <methodname>hashCode()</methodname> implementation is correct
                with respect to its related <methodname>equals()</methodname>
                method. However all <classname>Person</classname> instances of
                common <property>age</property> but different
                <property>name</property> will be defined to be different by
                our <methodname>equals(...)</methodname> method. But they will
                all share the same <methodname>hashCode()</methodname> value
                throughout. So our <methodname>hashCode()</methodname> method
                is not particularly good when it comes to distinguish objects.
                Adding the <property>name</property> property to our
                <methodname>hashCode()</methodname> calculation solves this
                issue:</para>

                <programlisting language="java">public class Person {
  ...
    @Override public int hashCode() {
        return ageInYears + 13 * name.hashCode();
    }
}</programlisting>
              </listitem>
            </orderedlist>
          </answer>
        </qandaentry>
      </qandadiv>
    </qandaset>
  </section>

  <section xml:id="sd1_exam_2021_winter_task3">
    <title>The average of three byte values</title>

    <qandaset defaultlabel="qanda" xml:id="sd1_exam_2021_winter_task3Qanda">
      <qandadiv>
        <qandaentry>
          <question>
            <para>A newbie programmer codes the following snippet:</para>

            <programlisting language="java">/**
 * The average of three values
 *
 * @param a First value
 * @param b Second value
 * @param c Third value
 *
 * @return Closest &lt;code&gt;byte&lt;/code&gt; value to ⅓ (a + b + c)
 */
public static byte getAverage(byte a, final byte b, final byte c) {
   a += b;
   a += c;
   a /= 3;
   return a;
}</programlisting>

            <para>A senior programming companion warns about two possible
            problems:</para>

            <orderedlist>
              <listitem>
                <para>The implementation is prone to overflow errors.</para>
              </listitem>

              <listitem>
                <para>The implementation will in many cases return
                unnecessarily inaccurate results.</para>
              </listitem>
            </orderedlist>

            <para>Explain both points in the answer box below.</para>

            <para>In addition provide a solution by modifying the above
            implementation without changing the method's signature. You may
            present your code in the answer box below as well.</para>

            <para>Alternatively correct the implementation of
            <package>de.hdm_stuttgart.mi.sd1.task4_no_unit_test</package>.<classname>Mathextend</classname>
            within your downloaded and imported <filename>exam.zip</filename>
            project using your IDEA IDE. In this case <emphasis role="red">Do
            not forget to export and upload after finishing by using task 1 of
            this examination</emphasis>.</para>

            <tip>
              <para><methodname
              xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Math.html#round(double)">Math.round(double)</methodname>
              might be your friend.</para>
            </tip>
          </question>

          <answer>
            <orderedlist>
              <listitem>
                <para>Biggest problem here: The operator <code
                language="java">+=</code>'s way of cycling through a <code
                language="java">byte</code>'s range when exceeding <code
                language="java"
                xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MAX_VALUE">Byte.MAX_VALUE</code>
                or <code language="java"
                xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MIN_VALUE">Byte.MIN_VALUE</code>
                boundaries. Consider:</para>

                <informaltable border="1">
                  <colgroup width="76%"/>

                  <colgroup width="24%"/>

                  <tr>
                    <th>Code</th>

                    <th>Output</th>
                  </tr>

                  <tr>
                    <td valign="top"><programlisting language="java">byte b = 127;
b += 1;
System.out.println("Result: " + b);</programlisting></td>

                    <td valign="top"><screen>Result: -128</screen></td>
                  </tr>

                  <tr>
                    <td valign="top"><programlisting language="java">byte b = -128;
b += -1;
System.out.println("Result: " + b);</programlisting></td>

                    <td valign="top"><screen>Result: +127</screen></td>
                  </tr>

                  <tr>
                    <td valign="top"><programlisting language="java">// Expecting 129 / 3 == +43
System.out.println("Result: " +
  getAverage((byte) 127, (byte) 1, (byte) 1));</programlisting></td>

                    <td valign="top"><screen>Result: -42</screen></td>
                  </tr>
                </informaltable>
              </listitem>

              <listitem>
                <para>Converting fractions to byte values is next on the list
                of troubles. The <code language="java">/=</code> operator will
                simply cut off fractional values rather then rounding them
                properly.</para>

                <para>Switching to real values we have <inlineequation>
                    <m:math display="inline">
                      <m:mrow>
                        <m:mrow>
                          <m:mfrac bevelled="true">
                            <m:mi>1</m:mi>

                            <m:mi>3</m:mi>
                          </m:mfrac>

                          <m:mo>⁢</m:mo>

                          <m:mrow>
                            <m:mo>(</m:mo>

                            <m:mrow>
                              <m:mi>1</m:mi>

                              <m:mo>+</m:mo>

                              <m:mi>1</m:mi>

                              <m:mo>+</m:mo>

                              <m:mi>0</m:mi>
                            </m:mrow>

                            <m:mo>)</m:mo>
                          </m:mrow>
                        </m:mrow>

                        <m:mo>=</m:mo>

                        <m:mi>0.66...</m:mi>
                      </m:mrow>
                    </m:math>
                  </inlineequation> . Our byte valued method should thus
                return a value of 1 rather than 0. However:</para>

                <informaltable border="1">
                  <colgroup width="76%"/>

                  <colgroup width="24%"/>

                  <tr>
                    <th>Code</th>

                    <th>Output</th>
                  </tr>

                  <tr>
                    <td valign="top"><programlisting language="java">System.out.println("Result: " + 
  getAverage((byte) 1, (byte) 1, (byte) 0));</programlisting></td>

                    <td valign="top"><screen>Result: 0</screen></td>
                  </tr>
                </informaltable>
              </listitem>
            </orderedlist>

            <para>Solving these flaws requires using a data type behaving free
            of overflow errors with respect to the given context of summing up
            three byte values. Choosing <code>short</code> is sufficient for
            adding either <code language="java"
            xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MAX_VALUE">Byte.MAX_VALUE</code>
            or <code language="java"
            xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MIN_VALUE">Byte.MIN_VALUE</code>
            even three times in a row.</para>

            <para>Dividing by 3 should be a floating point rather than an
            integer operation to avoid cutting off fractional values. On top
            we finally use the <classname
            xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Math.html">Math</classname><code
            language="java">.</code><methodname
            xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Math.html#round(double)">round(double)</methodname>
            method avoiding rounding errors like the one shown
            previously.</para>

            <para>Finally we need a cast for converting back the rounded
            value's type <code language="java">double</code> to the method's
            return type <code language="java">byte</code>. The final result
            reads:</para>

            <programlisting language="java">public static byte getAverage(final byte a, final byte b, final byte c) {

   short sum = a;
   sum += b;
   sum += c;
   final double avg = sum / 3.;   // Floating point rather than integer division
   return (byte) Math.round(avg); 
}

// Note: final short sum = a + b + c does not even compile as being explained at
// https://freedocs.mi.hdm-stuttgart.de/sd1_sect_arithmeticOperators.html#sd1_explainNoByteByteOperator</programlisting>

            <para>Given our sum being within range [-3 * -128, 3 * 127]
            dividing by three guarantees <code language="java">avg</code> to
            be within [-128, 127]. The <code language="java">(byte)</code>
            cast will thus safe with respect to overflow problems of our
            returned value.</para>
          </answer>
        </qandaentry>
      </qandadiv>
    </qandaset>
  </section>
</section>