Skip to content
This repository was archived by the owner on Jun 10, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
cache: maven

- name: Build with Maven
run: mvn -B package --file pom.xml
run: mvn -B package

- name: Run the Maven verify phase
run: mvn --batch-mode --update-snapshots verify
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target/
38 changes: 38 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
<junit.version>5.10.2</junit.version>
</properties>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
10 changes: 10 additions & 0 deletions src/main/java/com/mycompany/app/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mycompany.app;

public class App {
public static void main(String[] args) {
double val = Double.parseDouble("2.0");
Sqrt sqrt = new Sqrt(val);
double result = sqrt.calc();
System.out.println("Sqrt of " + val + " = " + result);
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/mycompany/app/Sqrt.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.mycompany.app;

public class Sqrt {
private static final double DEFAULT_DELTA = 1e-12;
private double delta = DEFAULT_DELTA;
private double arg;

public Sqrt(double arg) {
this.arg = arg;
}

public double average(double x, double y) {
return (x + y) / 2.0;
}

public boolean good(double guess, double x) {
if (x == 0.0) {
return Math.abs(guess) <= delta;
}
double ratio = x / guess;
return Math.abs(guess - ratio) <= delta * Math.max(1.0, Math.abs(guess));
}

public double improve(double guess, double x) {
return average(guess, x / guess);
}

public double iter(double guess, double x) {
for (int i = 0; i < 1000 && !good(guess, x); i++) {
guess = improve(guess, x);
}
return guess;
}

public double calc() {
if (arg < 0.0) {
throw new IllegalArgumentException("Argument must be non-negative: " + arg);
}
if (arg == 0.0) {
return 0.0;
}
double initialGuess = arg >= 1.0 ? arg / 2.0 : 1.0;
return iter(initialGuess, arg);
}
}
169 changes: 169 additions & 0 deletions src/test/java/com/mycompany/app/SqrtTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package com.mycompany.app;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;

class SqrtTest {
@Test
void constructorStoresArgumentAndCalcUsesIt() {
Sqrt sqrt = new Sqrt(9.0);
assertEquals(3.0, sqrt.calc(), 1e-7);
}

@Test
void averageReturnsMidpoint() {
Sqrt sqrt = new Sqrt(2.0);
assertEquals(5.0, sqrt.average(4.0, 6.0), 1e-12);
}

@Test
void averageWorksForNegativeAndPositiveValues() {
Sqrt sqrt = new Sqrt(2.0);
assertEquals(1.0, sqrt.average(-2.0, 4.0), 1e-12);
}

@Test
void goodReturnsTrueWhenGuessIsAccurateEnough() {
Sqrt sqrt = new Sqrt(2.0);
assertTrue(sqrt.good(Math.sqrt(2.0), 2.0));
}

@Test
void goodReturnsFalseWhenGuessIsNotAccurate() {
Sqrt sqrt = new Sqrt(2.0);
assertFalse(sqrt.good(1.0, 2.0));
}

@Test
void improvePerformsNewtonStep() {
Sqrt sqrt = new Sqrt(2.0);
assertEquals(1.5, sqrt.improve(1.0, 2.0), 1e-12);
}

@Test
void iterReturnsSameValueWhenGuessAlreadyGood() {
Sqrt sqrt = new Sqrt(16.0);
assertEquals(4.0, sqrt.iter(4.0, 16.0), 1e-12);
}

@Test
void iterConvergesFromRoughGuess() {
Sqrt sqrt = new Sqrt(16.0);
assertEquals(4.0, sqrt.iter(1.0, 16.0), 1e-7);
}

@Test
void calcForTwoIsAccurate() {
Sqrt sqrt = new Sqrt(2.0);
assertEquals(Math.sqrt(2.0), sqrt.calc(), 1e-7);
}

@Test
void calcForLargeNumberIsAccurate() {
Sqrt sqrt = new Sqrt(12345.0);
assertEquals(Math.sqrt(12345.0), sqrt.calc(), 1e-7);
}

@Test
void calcForFractionIsAccurate() {
Sqrt sqrt = new Sqrt(0.25);
assertEquals(0.5, sqrt.calc(), 1e-7);
}

@Test
void calcForZeroReturnsZero() {
Sqrt sqrt = new Sqrt(0.0);
assertEquals(0.0, sqrt.calc(), 0.0);
}

@Test
void calcForNegativeArgumentThrows() {
Sqrt sqrt = new Sqrt(-4.0);
assertThrows(IllegalArgumentException.class, () -> sqrt.calc());
}

@Test
void calcForScientificNotationValues() {
List<Double> values = List.of(
6.02214076e23,
9.10938356e-31,
1.602176634e-19,
2.99792458e8,
1.380649e-23
);
assertAll("scientific values",
values.stream()
.map(value -> () -> {
Sqrt sqrt = new Sqrt(value);
assertEquals(Math.sqrt(value), sqrt.calc(), Math.max(1e-12, Math.sqrt(value) * 1e-10));
})
);
}

@Test
void calcForExtremeTinyAndHugeValues() {
List<Double> values = List.of(
1e-300,
1e-200,
1e-100,
1e100,
1e200,
1e300
);
assertAll("extreme values",
values.stream()
.map(value -> () -> {
Sqrt sqrt = new Sqrt(value);
double expected = Math.sqrt(value);
assertEquals(expected, sqrt.calc(), Math.max(1e-10, Math.abs(expected) * 1e-9));
})
);
}

@Test
void calcForIrrationalAndUniqueConstants() {
List<Double> values = List.of(
Math.PI,
Math.E,
(1.0 + Math.sqrt(5.0)) / 2.0,
Math.PI * Math.E,
Math.log(2.0)
);
assertAll("irrational constants",
values.stream()
.map(value -> () -> {
Sqrt sqrt = new Sqrt(value * value);
assertEquals(value, sqrt.calc(), 1e-7);
})
);
}

@Test
void calcForCustomPrimeBasedSequence() {
List<Double> primes = List.of(
2.0, 3.0, 5.0, 7.0, 11.0, 13.0, 17.0, 19.0, 23.0, 29.0,
31.0, 37.0, 41.0, 43.0, 47.0
);
List<Double> values = new ArrayList<>();
for (int i = 0; i < primes.size(); i++) {
double prime = primes.get(i);
values.add(prime * prime + i * 0.12345);
values.add(prime * 1000.0 + i * 0.314159);
}
assertAll("prime-based unique sequence",
values.stream()
.map(value -> () -> {
Sqrt sqrt = new Sqrt(value);
assertEquals(Math.sqrt(value), sqrt.calc(), Math.max(1e-12, Math.sqrt(value) * 1e-10));
})
);
}
}
Loading