Add more decimal calculations

This commit is contained in:
MrLetsplay 2023-11-21 23:54:44 +01:00
parent 3f229dca29
commit 93845890c1
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
2 changed files with 79 additions and 4 deletions

View File

@ -44,7 +44,27 @@ public class Util {
return null; return null;
} }
public static void getIncrement(Identifier[] i1, Identifier[] i2, int offset) { public static int[] getIncremented(Identifier[] i1, Identifier[] i2, int offset) {
// TODO: can potentially be optimized by just calculating the index of the first non-zero digit (e.g. don't return array and discard it -> just return the index)
int[] delta = subtract(i2, i1, offset);
int firstNonZero = 0;
for(int i = 0; i < delta.length; i++) {
if(delta[i] != 0) {
firstNonZero = i;
break;
}
}
// Because of math, (firstNonZero + 1) >= i1.length (I think)
// then make the array 1 longer so we have space for the increment (which is one order of magnitude smaller)
int[] incremented = new int[firstNonZero + 2];
for(int i = 0; i < incremented.length; i++) {
incremented[i] = i <= i1.length ? i1[i].digit() : 0;
}
add1AtIndex(incremented, firstNonZero + 1); // last digit might be zero, which is ambigious, inc again
if(incremented[incremented.length - 1] == 0) add1AtIndex(incremented, firstNonZero + 1);
return incremented;
} }
/** /**
@ -67,7 +87,26 @@ public class Util {
} }
} }
if(carry == 1) throw new RuntimeException("Can't subtract numbers (are you sure a > b?)");
return diff; return diff;
} }
public static void add1AtIndex(int[] a, int index) {
// Technically, some of the overflow preventions are probably overkill since the biggest carry we can get is 1 (we're only adding a 1 somewhere after all)
int carry = 0;
for(int i = a.length - 1; i >= 0; i--) {
int dA = a[i];
int dB = (index == i ? 1 : 0) + carry;
carry = dB - (BASE - dA) + 1; // Calculate carry and be overflow-safe
if(carry < 0) carry = 0;
a[i] = carry != 0 ? -BASE + dA + dB : dA + dB; // Calculate sum of digits and be overflow-safe
}
if(carry == 1) throw new RuntimeException("Can't add numbers: Too large");
}
} }

View File

@ -1,6 +1,7 @@
package me.mrletsplay.shareclientcore; package me.mrletsplay.shareclientcore;
import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -13,21 +14,56 @@ public class DecimalTest {
public void testSimpleSubtraction() { public void testSimpleSubtraction() {
Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) }; Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) }; Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
assertArrayEquals(Util.subtract(a, b, 0), new int[] { 0, 1, 0 }); assertArrayEquals(new int[] { 0, 1, 0 }, Util.subtract(a, b, 0));
} }
@Test @Test
public void testCarrySubtraction() { public void testCarrySubtraction() {
Identifier[] a = new Identifier[] { new Identifier(2, 0), new Identifier(0, 0), new Identifier(4, 0) }; Identifier[] a = new Identifier[] { new Identifier(2, 0), new Identifier(0, 0), new Identifier(4, 0) };
Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) }; Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
assertArrayEquals(Util.subtract(a, b, 0), new int[] { 0, 9, 9 }); assertArrayEquals(new int[] { 0, Util.BASE - 1, Util.BASE - 1 }, Util.subtract(a, b, 0));
} }
@Test @Test
public void testOffsetSubtraction() { public void testOffsetSubtraction() {
Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) }; Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(4, 0) }; Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(4, 0) };
assertArrayEquals(Util.subtract(a, b, 1), new int[] { 0, 1 }); assertArrayEquals(new int[] { 0, 1 }, Util.subtract(a, b, 1));
}
@Test
public void testReversedInputFails() {
Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
assertThrows(RuntimeException.class, () -> Util.subtract(a, b, 0));
}
@Test
public void testSimpleAdd1() {
int[] a = new int[] { 0, 0 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 0, 1 }, a);
}
@Test
public void testCarryAdd1() {
int[] a = new int[] { 0, Util.BASE - 1 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 1, 0 }, a);
}
@Test
public void testCarryAdd1_2() {
int[] a = new int[] { 0, Util.BASE - 1, Util.BASE - 1 };
Util.add1AtIndex(a, 2);
assertArrayEquals(new int[] { 1, 0, 0 }, a);
}
@Test
public void testCarryAdd1_3() {
int[] a = new int[] { 0, Util.BASE - 1, Util.BASE - 1 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 1, 0, Util.BASE - 1 }, a);
} }
} }