<?xml version="1.0" encoding="UTF-8"?> <appendix version="5.0" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" 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 xml:id="sd1Appendix">Appendix</title> <section xml:id="sd1ExaminationHints"> <title>Examination hints</title> <para>Some programming tasks come with <xref linkend="glo_Junit"/> tests. Your personal score will depend on the number of successfully executing tests possibly weighted with factors modelling an individual test's significance.</para> <para>That said you should have a focus on completing units of work rather than <quote>nearly</quote> finishing a large number of tasks.</para> <caution> <para>Unit testing is quite relentless. It is different from high school where a wrong sign at the end of a calculation does not matter too much with respect to marking.</para> </caution> <para>You should <emphasis>actively</emphasis> train debugging programs: Watching a test fail is not so bad if you know how to <emphasis>systematically</emphasis> fix bugs. Several options are on offer:</para> <orderedlist> <listitem> <para>Use a debugger, typically the one provided by Eclipse. More specifically train debugging <xref linkend="glo_Junit"/> test cases individually to address failing tests one by one.</para> </listitem> <listitem> <para>Insert log statements into your implementation as being provided by log4j.</para> </listitem> </orderedlist> </section> <section xml:id="sd1ExternalSupplementaryExercises"> <title>Recommended external exercises</title> <glosslist> <glossentry> <glossterm>Bradley Kjell's <quote>Introduction to Computer Science using Java</quote></glossterm> <glossdef> <para><link xlink:href="https://chortle.ccsu.edu/java5/index.html">Original English version</link> and <link xlink:href="http://www.gailer-net.de/tutorials/java/java-toc.html">German translation</link>.</para> </glossdef> </glossentry> <glossentry> <glossterm><uri xlink:href="http://www.codeabbey.com">codeabbey.com</uri></glossterm> <glossdef> <para><link xlink:href="http://www.codeabbey.com/index/task_list">Problem list</link>.</para> </glossdef> </glossentry> <glossentry> <glossterm><uri xlink:href="https://rosettacode.org">rosettacode.org</uri></glossterm> <glossdef> <para><link xlink:href="https://rosettacode.org/wiki/Category:Programming_Tasks">Programming tasks</link> (including solutions for multiple languages).</para> </glossdef> </glossentry> <glossentry> <glossterm>reddit.com</glossterm> <glossdef> <para><link xlink:href="https://www.reddit.com/r/dailyprogrammer">Daily Programmer</link>.</para> </glossdef> </glossentry> <glossentry> <glossterm xlink:href="https://projecteuler.net">Project Euler</glossterm> <glossdef> <para>You will have to register without requiring an E-Mail. This is only intended to provide a profile for keeping track of your exercises' status. The following exercises are meant to be useful with respect to the current lectures and have in part been added as regular exercises to these lecture notes as well:</para> <para><link xlink:href="https://projecteuler.net/problem=1">1</link>, <link xlink:href="https://projecteuler.net/problem=2">2</link>, <link xlink:href="https://projecteuler.net/problem=4">4</link>, <link xlink:href="https://projecteuler.net/problem=5">5</link>, <link xlink:href="https://projecteuler.net/problem=8">8</link>, <link xlink:href="https://projecteuler.net/problem=9">9</link>, <link xlink:href="https://projecteuler.net/problem=11">11</link>.</para> </glossdef> </glossentry> <glossentry> <glossterm>Java Programming Tutorial</glossterm> <glossdef> <para xlink:href="https://www3.ntu.edu.sg/home/ehchua/programming/java/J2a_BasicsExercises.html">Basic and more difficult exercises</para> </glossdef> </glossentry> <glossentry> <glossterm>Java Programming Exercises</glossterm> <glossdef> <para>Take the <link xlink:href="https://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/en/java.html">easier exercises</link>.</para> </glossdef> </glossentry> </glosslist> </section> <section version="5.0" xml:id="sd1SectExamAmendingProjects"> <title>Examination bonus point project</title> <para>Each participant may start a project to gain a bonus with respect to the final examination. This bonus is given as a percentage and will be added to your final examinations mark. Possible values depending on a project's achievements are:</para> <itemizedlist> <listitem> <para>0%</para> </listitem> <listitem> <para>5%</para> </listitem> <listitem> <para>10%</para> </listitem> </itemizedlist> <para>So if the examination's result is 85% a bonus of 10% will result in a mark corresponding to 95% of a regular exam result.</para> <section xml:id="sd1SectProjectCriteria"> <title>Marking criteria / Hints</title> <orderedlist> <listitem> <para>You are expected to work as a team of three partners.</para> </listitem> <listitem> <para>Using the <link xlink:href="https://version.mi.hdm-stuttgart.de/">MI git SCM</link> is a plus with respect to the project's evaluation.</para> </listitem> <listitem> <para>Your team is expected to supply a Maven project based on the MI <quote>Maven archetype quickstart</quote> available from <uri xlink:href="https://maven.mi.hdm-stuttgart.de/archetype-catalog.xml">https://maven.mi.hdm-stuttgart.de</uri>.</para> </listitem> <listitem> <para>You are expected to provide good internal code documentation with respect both to method signatures (<xref linkend="glo_Javadoc"/>) and method implementation. Possible problems involve:</para> <glosslist> <glossentry> <glossterm>Compile time warnings</glossterm> <glossdef> <para>Activate most compiler warnings at <guimenuitem>Window</guimenuitem> --> <guimenuitem>Preferences</guimenuitem> --> <guimenuitem>Java</guimenuitem> --> <guimenuitem>Compiler</guimenuitem> --><guimenuitem>Errors/Warnings</guimenuitem>. This will show potential compile time problems like dead / unnecessary / unreachable code, unused variable values, shadowing conflicts and so on:</para> <mediaobject> <imageobject> <imagedata fileref="Ref/Fig/bonusJavadocCompileTimeProblems.png"/> </imageobject> </mediaobject> </glossdef> </glossentry> <glossentry xml:id="sd1BonusprojectActivateJavadocWarnings"> <glossterm><xref linkend="glo_Javadoc"/> mismatches</glossterm> <glossdef> <para>Your method's formal parameters, their type and a method's return type must match your documentation. In the following code snippet the method <methodname>getPrimeFactors(...)</methodname> does have neither a parameter named <property>prime</property> nor <property>frequency</property>:</para> <mediaobject> <imageobject> <imagedata fileref="Ref/Fig/bonusJavadocMismatch.png"/> </imageobject> </mediaobject> <tip> <itemizedlist> <listitem> <para>Activate most <xref linkend="glo_Javadoc"/> related warnings in your IDE globally per workspace below <guimenuitem>Window</guimenuitem> --> <guimenuitem>Preferences</guimenuitem> --> <guimenuitem>Java</guimenuitem> --> <guimenuitem>Compiler</guimenuitem> --> <guimenuitem>Javadoc</guimenuitem>. You may as well activate them as per project settings below <guimenuitem>Project</guimenuitem> --> <guimenuitem>Properties</guimenuitem> --> <guimenuitem>Java Compiler</guimenuitem> --> <guimenuitem>Javadoc</guimenuitem> if ticking <quote>Project specific settings</quote>.</para> </listitem> <listitem> <para>Actually generate the <xref linkend="glo_Javadoc"/> <xref linkend="glo_HTML"/> and see whether it will be useful / sufficient to a programmer using your <code>public</code> interface.</para> </listitem> </itemizedlist> </tip> </glossdef> </glossentry> </glosslist> </listitem> <listitem> <para>You are expected to provide meaningful unit tests:</para> <itemizedlist> <listitem> <para>Try to cover all your implementation code and not just isolated modules / methods.</para> </listitem> <listitem> <para>If methods allow for null values write suitable tests.</para> </listitem> <listitem> <para>Test special cases: If a method expects i.e. an array of strings it may be allowed having zero length.</para> </listitem> </itemizedlist> </listitem> <listitem> <para>Your resulting project should be easily installable / runnable.</para> <itemizedlist> <listitem> <para>Maven is a good starting point with respect both to test integration and cross platform (Unix / Windows / Apple) portability.</para> </listitem> <listitem> <para>Avoid dependencies to local filesystem resources like <filename>c:\users\xyz\testdata.txt</filename>.</para> </listitem> </itemizedlist> <tip> <para>Test the deployability of your project by installing it on an untouched target platform (possibly of a different hard/software architecture) and execute <command>mvn</command> <option>test</option> (provided you do have written meaningful unit tests).</para> </tip> </listitem> </orderedlist> </section> <section xml:id="sd1SectProjectGrep"> <title>Poor man's <xref linkend="glo_UNIX"/> <command xlink:href="http://linux.die.net/man/1/grep">grep</command>.</title> <para>The <xref linkend="glo_UNIX"/> operating system provides a command <command xlink:href="http://linux.die.net/man/1/grep">grep</command> which allows for retrieving occurrences of a given string in text files. We consider an example text file <filename>input.txt</filename> containing four lines:</para> <programlisting language="none" linenumbering="numbered">Roses are nice flowers. Red wine is tasty The red cross acts worldwide Mayflower used to be a ship.</programlisting> <para>We search this file <filename>input.txt</filename> for the occurrence of the string <quote>flower</quote> being contained in lines 1 and 4:</para> <programlisting language="none">> grep <emphasis role="bold">flower</emphasis> input.txt Roses are nice <emphasis role="bold">flower</emphasis>s. May<emphasis role="bold">flower</emphasis> used to be a ship.</programlisting> <para>Thus the <command xlink:href="http://linux.die.net/man/1/grep">grep</command> command echoes all lines containing the search string in question to standard output. Adding the command line option <option>-i</option> allows for case insensitive searches:</para> <programlisting language="none" linenumbering="unnumbered">> grep <option>-i</option> <emphasis role="bold">red</emphasis> input.txt <emphasis role="bold">Red</emphasis> wine is tasty The <emphasis role="bold">red</emphasis> cross acts worldwide</programlisting> <para>This time all possible variants like <quote>Red</quote>, <quote>red</quote>, <quote>RED</quote> and so on will match.</para> <para><command xlink:href="http://linux.die.net/man/1/grep">grep</command> also allows for searching multiple files. Consider a second file <filename>inputSecond.txt</filename>:</para> <programlisting language="none" linenumbering="numbered">Errors will show up in red. Let's start bug fixing</programlisting> <para>We may search for case insensitive (<option>-i</option> again) appearances of <quote>red</quote> within both files:</para> <programlisting language="none" linenumbering="unnumbered">> grep -i <emphasis role="bold">red</emphasis> input.txt inputSecond.txt input.txt:<emphasis role="bold">Red</emphasis> wine is tasty input.txt:The <emphasis role="bold">red</emphasis> cross acts worldwide inputSecond.txt:Errors will show up in <emphasis role="bold">red</emphasis>.</programlisting> <para>Finally the <option>-l</option> option will filter individual appearances just showing filenames containing matches:</para> <programlisting language="none">> grep -l Red input.txt inputSecond.txt input.txt</programlisting> <para>In contrast a case insensitive search combining both <option>-i</option> and <option>-l</option> options yields:</para> <programlisting language="none">> grep -i -l Red input.txt inputSecond.txt input.txt inputSecond.txt</programlisting> <para>The <command xlink:href="http://linux.die.net/man/1/grep">grep</command> command may read its input from standard input allowing for <link xlink:href="https://en.wikipedia.org/wiki/Pipeline_(Unix)">pipes</link>. This way another command's output feeds into a subsequently executed command. As an example consider a recursive search for HTML files using the <link xlink:href="http://linux.die.net/man/1/find">find</link> command:</para> <programlisting language="none">> find . -name \*.html ./Sd1/Wc/wc/Testdata/input.html ./Sda1/rdbmsXml2Html/TestData/climbingprice.html ./Sda1/NoCast/src/main/resources/gallery.html ./Sda1/Jdom/Html2Html/src/main/resources/imageExampleNew.html ./Sda1/Jdom/Html2Html/src/main/resources/imageExample.html ./Sda1/VerifyImgAccess/fileextref.html</programlisting> <para>We want to restrict the above list to pathnames containing the string <quote>Example</quote>. This may be achieved by <link xlink:href="https://en.wikipedia.org/wiki/Pipeline_(Unix)">piping</link> the <link xlink:href="http://linux.die.net/man/1/find">find</link> command's output as input to <command xlink:href="http://linux.die.net/man/1/grep">grep</command> searching for the occurrence of the string <quote>Example</quote>. Technically both processes get connected by means of the pipe symbol <quote>|</quote>:</para> <programlisting language="none">> find . -name \*.html|grep Example ./Sda1/Jdom/Html2Html/src/main/resources/imageExampleNew.html ./Sda1/Jdom/Html2Html/src/main/resources/imageExample.html</programlisting> <tip> <orderedlist> <listitem> <para>Read about reading from files by using instances of <classname xlink:href="http://www.tutorialspoint.com/java/io/bufferedreader_readline.htm">java.io.BufferedReader</classname>.</para> </listitem> <listitem> <para>Reading from standard input may be achieved by:</para> <programlisting language="java">final BufferedReader source = new BufferedReader(new InputStreamReader(System.in)); ...</programlisting> </listitem> <listitem> <para>You may create an executable jar archive using Maven. Starting from the <code>mi-mavem-archetype-quickstart</code> your <filename>pom.xml</filename> already contains a blueprint. Just insert your class containing the entry <methodname>main(...)</methodname> method (i.e. <classname>de.hdm_stuttgart.mi.sd1.grep.Grep</classname> in the current example) accordingly:</para> <programlisting language="xml"><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.1</version> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Main-Class><emphasis role="bold">de.hdm_stuttgart.mi.sd1.grep.Grep</emphasis></Main-Class> </manifestEntries> </transformer> </transformers> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin></programlisting> <para>Running <command>mvn</command> <option>install</option> will create an executable jar file like e.g. <filename>~/.m2/repository/de/hdm-stuttgart/mi/sd1/grep/0.9/grep-0.9.jar</filename> with <quote>~</quote> denoting your home directory:</para> <programlisting language="none">> mvn install [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building grep 0.9 [INFO] ------------------------------------------------------------------------ ... ------------------------------------------------------- T E S T S ------------------------------------------------------- Running de.hdm_stuttgart.mi.sd1.grep.CommandLineTest Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.757 sec Results : Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] Installing /home/goik/workspace/sd-project-summer/grep/target/grep-0.9.jar to /home/goik/.m2/repository/de/hdm-stuttgart/mi/sd1/grep/0.9/grep-0.9.jar ... </programlisting> <para>Due to our <code><Main-Class>de.hdm_stuttgart.mi.sd1.grep.Grep</Main-Class></code> declaration in <filename>pom.xml</filename> this jar file is executable:</para> <programlisting language="none">> java -jar ~/.m2/repository/de/hdm-stuttgart/mi/sd1/grep/0.9/grep-0.9.jar No search string given Usage: grep [-i] [-l] searchString [file 1] [file 2] ...</programlisting> <para>There are further simplification steps:</para> <orderedlist> <listitem> <para>Making the jar file executable using <command xlink:href="http://linux.die.net/man/1/chmod">chmod</command> allows for omitting the <command>java</command> command:</para> <programlisting language="none">> chmod +x ~/.m2/repository/de/hdm-stuttgart/mi/sd1/grep/0.9/grep-0.9.jar > ~/.m2/repository/de/hdm-stuttgart/mi/sd1/grep/0.9/grep-0.9.jar No search string given Usage: grep [-i] [-l] searchString [file 1] [file 2] ...</programlisting> <para>Notice <quote>~</quote> representing a user's home directory.</para> </listitem> <listitem> <para>We may copy the jar archive to a standard location containing executable commands:</para> <programlisting language="none">> mkdir ~/bin > > cp ~/.m2/repository/de/hdm-stuttgart/mi/sd1/grep/0.9/grep-0.9.jar ~/bin/jgrep > > ~/bin/jgrep No search string given Usage: grep [-i] [-l] searchString [file 1] [file 2] ...</programlisting> </listitem> <listitem> <para>We may add this directory to the set of directories being searched by the operating system's command line interpreter for executable commands. This is being achieved by either creating or modifying a file <filename>~/.profile</filename> in the user's home directory using a text editor. <filename>~/.profile</filename> should contain:</para> <programlisting language="none">PATH="$HOME/bin:$PATH"</programlisting> <para>After logging out and on again your PATH environment variable should contain your <filename>~/bin</filename> component:</para> <programlisting language="none">> echo $PATH <emphasis role="bold">/home/goik/bin</emphasis>:/usr/local/sbin:/usr/local/bin:/usr/...</programlisting> <para>You should now be able to call <command>jgrep</command> from arbitrary filesystem locations:</para> <programlisting language="none">> cd Desktop/ > cat Testdata/input.txt | ./bin/mygrep red The red cross acts worldwide</programlisting> </listitem> </orderedlist> </listitem> <listitem xml:id="sd1ProjectGrepUnitTestingHint"> <para>Testing requires capturing of output being generated by e.g. <methodname xlink:href="https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#out">System.out</methodname><code>.</code><methodname xlink:href="https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html#println-java.lang.String-">println(...)</methodname> calls. Consider the following code writing the string <quote>Hello World!</quote> to standard output:</para> <programlisting language="java">public class App { /** * @param args Unused */ public static void main( String[] args ) { System.out.print( "Hello World!" ); } }</programlisting> <para>We want to set up a <productname>Junit</productname> test which captures the output to compare it with the expected string value <code>"Hello World!"</code>. Following <uri xlink:href="http://stackoverflow.com/questions/1119385/junit-test-for-system-out-println">http://stackoverflow.com/questions/1119385/junit-test-for-system-out-println</uri> we redefine the standard output stream by a private instance of <classname xlink:href="https://docs.oracle.com/javase/8/docs/api/java/io/ByteArrayOutputStream.html">java.io.ByteArrayOutputStream</classname>. Due to <productname>Junit</productname>'s <classname xlink:href="http://junit.sourceforge.net/javadoc/org/junit/Before.html">@Before</classname> and <classname xlink:href="http://junit.sourceforge.net/javadoc/org/junit/After.html">@After</classname> annotations this instance replaces <classname xlink:href="https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#out">System.out</classname> during our tests:</para> <programlisting language="java">import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * Unit test for simple App. */ public class AppTest { private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); <classname xlink:href="http://junit.sourceforge.net/javadoc/org/junit/Before.html">@Before</classname> public void setUpStreams() { System.setOut(new PrintStream(outContent)); } <classname xlink:href="http://junit.sourceforge.net/javadoc/org/junit/After.html">@After</classname> public void cleanUpStreams() { System.setOut(null); outContent.reset(); } /** * Test method accessing output generated by System.out.println(...) calls. */ @Test public void testApp() { App.main(new String[]{}); // Calling main() method printing "Hello World!" Assert.assertEquals("Hello World!", outContent.toString()); } }</programlisting> </listitem> </orderedlist> </tip> </section> <section xml:id="sd1ProjectSieveErathostenes"> <title>Project <link xlink:href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Euler.27s_Sieve">Euler's sieve</link> (Winter 2015)</title> <para>The project's goal is about:</para> <itemizedlist> <listitem> <para>Generating all prime numbers of type <code>int</code>.</para> </listitem> <listitem> <para>Using this set of pregenerated prime numbers for decomposing arbitrary <code>int</code> values into prime factors e.g.:</para> <para>1050 = 2 * 3 * 5 * 5 * 7</para> </listitem> </itemizedlist> <para>We start with the first task by implementing the <link xlink:href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Euler.27s_Sieve">Euler sieve algorithm</link>. We may use a boolean array representing e.g. the first 100 primes:</para> <programlisting language="java">boolean[] nonPrimes = new boolean[100];</programlisting> <para>This array will initially be filled with 100 <code>false</code> values. The idea is using the <link xlink:href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Euler.27s_Sieve">Euler sieve algorithm</link> to turn all non-prime value to <code>true (t)</code> and leaving al prime index values at <code>false (f)</code>:</para> <programlisting language="non">Index | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14 ... ------+--+--+--+--+--+--+--+--+--+--+---+---+---+---+--- ... value | t| t| f| f| t| f| t| f| t| t| t| f| t| f| t ...</programlisting> <para>Since we intend to deal with a large number <code xlink:href="https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#MAX_VALUE">Integer.MAX_VALUE</code> of values (rather than just 100 ) we only consider odd values since even numbers are never prime except for the value 2. Thus 0 will represent 1, 1 will represent 3 and n will represent 2 * n + 1:</para> <programlisting language="non">Index | 0| 1| 2| 3| 4| 5| 6| 7| ... -----------+--+--+--+--+--+---+---+---+ ... represents | 1| 3| 5| 7| 9| 11| 13| 15| ... -----------+--+--+--+--+--+---+---+---+ ... value | t| f| f| f| t| f| f| t| ...</programlisting> <para>This requires a boolean array of just <code xlink:href="https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#MAX_VALUE">Integer.MAX_VALUE / 2</code>. Start from the following skeleton:</para> <programlisting language="java">public class Sieve { final boolean[] nonPrimes; final int numPrimesFound; /** * Creating a prime number Euler variant sieve * * @param limit The last value to be considered. May or may not be prime. * */ public Sieve(final int limit) { ...// initialize nonPrimes and numPrimesFound. } ... /** * Test if a given value is prime or not * * @param candidate The value in question. * * @return True if value is prime, false otherwise. */ public boolean isPrime(final int candidate) { // Based on nonPrimes array ... } }</programlisting> <tip> <para>Decompose the <link xlink:href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Euler.27s_Sieve">Euler sieve algorithm</link> into smaller tasks and write appropriate tests. Start with small <code>limit</code> values (like 20) and extend to <code xlink:href="https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#MAX_VALUE">Integer.MAX_VALUE</code> step by step.</para> </tip> <para>Once you've finished implementing the sieve continue by implementing the second task of prime decomposition. We recall the initial example:</para> <para>1050 = 2 * 3 * 5 * 5 * 7</para> <para>So the primes 2, 3 and 7 appear with frequency 1 whereas 5 appears with frequency 2. For meaningful operations we introduce a new class combining a prime number and its corresponding frequency of appearance to represent prime factor decompositions appropriately:</para> <programlisting language="java">/** * Representing a single prime factor among with its * frequency. * */ public class PrimeFrequency { /** * The prime's immutable value. */ public final int prime; /** * The prime's frequency of appearance. */ int frequency; /** * @param prime {@link #prime} * @param frequency The prime's frequency of appearance. */ public PrimeFrequency(final int prime, final int frequency) { this.prime = prime; this.frequency = frequency; } /** * @return The prime factor's frequency of appearance. */ public int getFrequency() { return frequency; } /** * change the given frequency value. * @param frequency change by this value. */ public void addFrequency(@SuppressWarnings("hiding") final int frequency) { this.frequency += frequency; } @Override public boolean equals(final Object obj) { ... } }</programlisting> <para>Now 2 * 3 * 5 * 5 * 7 may be represented by three (not four!) instances of <code>PrimeFrequency</code>. In order to represent the whole product implement a second container:</para> <programlisting language="java">/** * Representing integer values by an ordered set of prime factors among with * their frequencies of appearance. * */ public class PrimeFrequencySet { private final static int initialCapacity = 16; private PrimeFrequency[] store = new PrimeFrequency[initialCapacity]; // May grow due to new factors. /** * Searching for the existence of a {@link PrimeFrequency} with a matching * prime value (frequency may be different!). * * Example: If the set contains the prime values {3, 7, 11} (we ignore * frequencies) then searching for: * <ul> * <li>3 return index 0</li> * <li>11 returns index 2</li> * <li>5 return -2</li> * <li>13 returns -3</li> * <li>2 returns -1</li> * </ul> * * @param primeFrequency The candidate to be looked up. * * @return If a prime value match exists return its index. If no match * exists return the negative value of the first index belonging to a set * value having a larger prime value than the candidate (the "natural" * insertion point) minus 1 (see example). */ public int find(final PrimeFrequency primeFrequency) { ... } /** * Either add a new prime or just add a prime's frequency to an existing one. * * @param primeFrequency If the prime is already in the current set, add its * frequency. Otherwise insert the new element preserving the order of prime * values. */ public void add(final PrimeFrequency primeFrequency) { ... } /** * @return The count of all prime factors. */ public int getLength() { ... } /** * The prime factor corresponding to a given index. * @param index . * @return . */ public PrimeFrequency get(int index) { ... } /** * @return All prime factors among with their respective frequencies. */ public PrimeFrequency[] get() { ... } }</programlisting> <para>This allows for decomposing arbitrary <code>int</code> values into their prime factors. We show a unit test example:</para> <programlisting language="java">/** * Prime factor decomposition. */ public class FactorTest { final Sieve sieve = new Sieve(100000); @Test public void test2 () { PrimeFrequencySet pfs = sieve.getPrimeFactors(12); <co linkends="sd1ListingTestPrimeFactorDecompose-1" xml:id="sd1ListingTestPrimeFactorDecompose-1-co"/> Assert.assertEquals(2, pfs.getLength()); <co linkends="sd1ListingTestPrimeFactorDecompose-2" xml:id="sd1ListingTestPrimeFactorDecompose-2-co"/> Assert.assertEquals(new PrimeFrequency(2, 2), pfs.get(0)); <co linkends="sd1ListingTestPrimeFactorDecompose-3" xml:id="sd1ListingTestPrimeFactorDecompose-3-co"/> Assert.assertEquals(new PrimeFrequency(3, 1), pfs.get(1)); <co linkends="sd1ListingTestPrimeFactorDecompose-4" xml:id="sd1ListingTestPrimeFactorDecompose-4-co"/> } }</programlisting> <calloutlist> <callout arearefs="sd1ListingTestPrimeFactorDecompose-1-co" xml:id="sd1ListingTestPrimeFactorDecompose-1"> <para>Decomposing 12 into 2 * 2 * 3.</para> </callout> <callout arearefs="sd1ListingTestPrimeFactorDecompose-2-co" xml:id="sd1ListingTestPrimeFactorDecompose-2"> <para>We expect two factors:</para> <orderedlist> <listitem> <para>Prime factor 2 having frequency 2.</para> </listitem> <listitem> <para>Prime factor 3 having frequency 1.</para> </listitem> </orderedlist> </callout> <callout arearefs="sd1ListingTestPrimeFactorDecompose-3-co" xml:id="sd1ListingTestPrimeFactorDecompose-3"> <para>Check for first prime factor 2 of frequency 2.</para> </callout> <callout arearefs="sd1ListingTestPrimeFactorDecompose-4-co" xml:id="sd1ListingTestPrimeFactorDecompose-4"> <para>Check for second prime factor 3 of frequency 1.</para> </callout> </calloutlist> <para>For better illustration we provide the following example:</para> <programlisting language="java">public class Driver { /** * @param args Unused */ public static void main( String[] args ) { final Sieve sieve = new Sieve(Integer.MAX_VALUE); int value = Integer.MAX_VALUE; System.out.println("Value " + value + " is " + (sieve.isPrime(value)? "" : "not") + " prime."); value--; // Even Value System.out.println("Value " + value + " is " + (sieve.isPrime(value)? "" : "not") + " prime."); value --; // Non-prime as well. System.out.println("Value " + value + " is " + (sieve.isPrime(value)? "" : "not") + " prime."); value = Integer.MAX_VALUE - 1; final PrimeFrequencySet pfs = sieve.getPrimeFactors(value); System.out.print(value + " = "); String separator = ""; for (PrimeFrequency pf : pfs.get()) { for (int i = 0; i < pf.getFrequency(); i++) { System.out.print(separator + pf.prime); separator = " * "; } } System.out.println(); } }</programlisting> <para>This yields the following output:</para> <programlisting language="none">Value 2147483647 is prime. Value 2147483646 is not prime. Value 2147483645 is not prime. 2147483646 = 2 * 3 * 3 * 7 * 11 * 31 * 151 * 331</programlisting> <para>Depending on your implementation you may encounter the following heap memory related error:</para> <programlisting language="none">Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at de.hdm_stuttgart.mi.prim.sieve.Sieve.initSieve(Sieve.java:75) at de.hdm_stuttgart.mi.prim.sieve.Sieve.<init>(Sieve.java:60) at de.hdm_stuttgart.mi.prim.Driver.main(Driver.java:19)</programlisting> <para>The <xref linkend="glo_Java"/> virtual machine by default may not provide enough heap space. You may enlarge the default allocation by setting the <option>-Xmx</option>. Eclipse provides a convenient way by means of a run time configuration (Menu Run --> Run Configurations):</para> <informalfigure> <mediaobject> <imageobject> <imagedata fileref="Ref/Fig/primDriverRunConfigOverview.bmp"/> </imageobject> </mediaobject> </informalfigure> <para>Clicking the <quote>Arguments</quote> tab allows for setting the respective VM heap setting:</para> <informalfigure> <mediaobject> <imageobject> <imagedata fileref="Ref/Fig/primDriverRunConfigVmOptions.bmp"/> </imageobject> </mediaobject> </informalfigure> <para>This allows for running your application with a maximum of 4 gigabytes of heap space.</para> <para>With respect to automated unit testing (<command>mvn</command> <option>test</option>)you may want to set the same value in you <filename>pom.xml</filename> file</para> <programlisting language="xml"><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <emphasis role="bold"><argLine>-Xmx4G</argLine></emphasis> </configuration> </plugin></programlisting> </section> </section> </appendix>