L
@SeppJ sagte in Zahlen mit Anzahl Nachkommastellen:
Multipliziere deinen Wert mit 10^(Anzahl gewünschter Stellen);
Ja ... aber ohne Limitierungen funktioniert der Math.pow(10, decimalPlaces)-Ansatz leider nicht:
public class NumbersTool {
public static String formatNumber(double number, int decimalPlaces, char decimalSeparator) {
if (number < -1e14 || number > 1e14) {
throw new IllegalArgumentException("number must be between -1e14 and 1e14");
}
if (decimalPlaces <= 0) {
throw new IllegalArgumentException("decimalPlaces must be greater than 0");
}
if (decimalPlaces > 10) {
throw new IllegalArgumentException("decimalPlaces must be less than or equal to 10");
}
double number1 = number * Math.pow(10, decimalPlaces);
// number > 0
// ? Math.nextUp(number * Math.pow(10, decimalPlaces))
// : Math.nextDown(number * Math.pow(10, decimalPlaces));
long number2 = (long) number1;
if (number2 == -1) {
return "-0" + decimalSeparator + "0".repeat(decimalPlaces - 1) + "1";
}
if (number2 == 1) {
return "0" + decimalSeparator + "0".repeat(decimalPlaces - 1) + "1";
}
String number3 = Long.toString(number2);
if (number3.length() < decimalPlaces || number2 < 0 && number3.length() < decimalPlaces + 2) {
if (number2 < 0) {
number3 = "-" + "0".repeat(decimalPlaces - number3.length() + 2) + number3.substring(1);
} else if (number2 < 10) {
number3 += "0".repeat(decimalPlaces - number3.length() + 1);
} else {
number3 = "0".repeat(decimalPlaces - number3.length()) + number3;
}
}
int split = number3.length() - decimalPlaces;
if (split == 0) {
return "0" + decimalSeparator + number3;
}
return number3.substring(0, split) + decimalSeparator + number3.substring(split);
}
}
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class NumbersToolTest {
@Test
void formatNumber_0_exceptions() {
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(123.12, -2, ','));
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(123.12, -1, ','));
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(123.12, 0, ','));
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(123.12, 11, ','));
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(123.12, 12, ','));
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(123.12, 13, ','));
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(1e15, 2, ','));
assertThrows(IllegalArgumentException.class, () -> NumbersTool.formatNumber(-1e15, 2, ','));
}
@Test
void formatNumber_1_shortNumbers() {
double n1 = 123.12;
assertEquals("123,1", NumbersTool.formatNumber(n1, 1, ','));
assertEquals("123,12", NumbersTool.formatNumber(n1, 2, ','));
assertEquals("123,120", NumbersTool.formatNumber(n1, 3, ','));
assertEquals("123,1200", NumbersTool.formatNumber(n1, 4, ','));
assertEquals("123,12000", NumbersTool.formatNumber(n1, 5, ','));
assertEquals("123,120000", NumbersTool.formatNumber(n1, 6, ','));
assertEquals("123,1200000", NumbersTool.formatNumber(n1, 7, ','));
assertEquals("123,12000000", NumbersTool.formatNumber(n1, 8, ','));
assertEquals("123,120000000", NumbersTool.formatNumber(n1, 9, ','));
assertEquals("123,1200000000", NumbersTool.formatNumber(n1, 10, ','));
double n2 = 123;
for (int i = 1; i <= 10; i++) {
assertEquals("123," + "0".repeat(i), NumbersTool.formatNumber(n2, i, ','));
}
}
@Test
void formatNumber_2_longNumber() {
double n = Math.PI; // 3.14159265358979323846
assertEquals("3,1", NumbersTool.formatNumber(n, 1, ','));
assertEquals("3,14", NumbersTool.formatNumber(n, 2, ','));
assertEquals("3,141", NumbersTool.formatNumber(n, 3, ','));
assertEquals("3,1415", NumbersTool.formatNumber(n, 4, ','));
assertEquals("3,14159", NumbersTool.formatNumber(n, 5, ','));
assertEquals("3,141592", NumbersTool.formatNumber(n, 6, ','));
assertEquals("3,1415926", NumbersTool.formatNumber(n, 7, ','));
assertEquals("3,14159265", NumbersTool.formatNumber(n, 8, ','));
assertEquals("3,141592653", NumbersTool.formatNumber(n, 9, ','));
assertEquals("3,1415926535", NumbersTool.formatNumber(n, 10, ','));
}
@Test
void formatNumber_3_negativeNumber() {
double n = -1.9911;
assertEquals("-1,9", NumbersTool.formatNumber(n, 1, ','));
assertEquals("-1,99", NumbersTool.formatNumber(n, 2, ','));
assertEquals("-1,991", NumbersTool.formatNumber(n, 3, ','));
assertEquals("-1,9911", NumbersTool.formatNumber(n, 4, ','));
assertEquals("-1,99110", NumbersTool.formatNumber(n, 5, ','));
assertEquals("-1,991100", NumbersTool.formatNumber(n, 6, ','));
assertEquals("-1,9911000", NumbersTool.formatNumber(n, 7, ','));
assertEquals("-1,99110000", NumbersTool.formatNumber(n, 8, ','));
assertEquals("-1,991100000", NumbersTool.formatNumber(n, 9, ','));
assertEquals("-1,9911000000", NumbersTool.formatNumber(n, 10, ','));
}
@Test
void formatNumber_4_zero() {
double n = 0;
assertEquals("0,0", NumbersTool.formatNumber(n, 1, ','));
assertEquals("0,00", NumbersTool.formatNumber(n, 2, ','));
assertEquals("0,000", NumbersTool.formatNumber(n, 3, ','));
assertEquals("0,0000", NumbersTool.formatNumber(n, 4, ','));
assertEquals("0,00000", NumbersTool.formatNumber(n, 5, ','));
assertEquals("0,000000", NumbersTool.formatNumber(n, 6, ','));
assertEquals("0,0000000", NumbersTool.formatNumber(n, 7, ','));
assertEquals("0,00000000", NumbersTool.formatNumber(n, 8, ','));
assertEquals("0,000000000", NumbersTool.formatNumber(n, 9, ','));
assertEquals("0,0000000000", NumbersTool.formatNumber(n, 10, ','));
}
@Test
void formatNumber_5_edgeCaseLargeDecimalPlaces() {
double n = 1.0 / 3.0; // 0.3333333333333333...
for (int i = 1; i <= 10; i++) {
assertEquals("0," + "3".repeat(i), NumbersTool.formatNumber(n, i, ','));
}
}
@Test
void formatNumber_6_edgeCaseVerySmallNumber() {
double n1 = 0.0000000001;
for (int i = 1; i <= 9; i++) {
assertEquals("0," + "0".repeat(i), NumbersTool.formatNumber(n1, i, ','));
}
assertEquals("0,0000000001", NumbersTool.formatNumber(n1, 10, ','));
double n2 = -0.0000000001;
for (int i = 1; i <= 9; i++) {
assertEquals("0," + "0".repeat(i), NumbersTool.formatNumber(n2, i, ','));
}
assertEquals("-0,0000000001", NumbersTool.formatNumber(n2, 10, ','));
double n3 = 0.000000000111;
for (int i = 1; i <= 9; i++) {
assertEquals("0," + "0".repeat(i), NumbersTool.formatNumber(n3, i, ','));
}
assertEquals("0,0000000001", NumbersTool.formatNumber(n3, 10, ','));
double n4 = -0.000000000111;
for (int i = 1; i <= 9; i++) {
assertEquals("0," + "0".repeat(i), NumbersTool.formatNumber(n4, i, ','));
}
assertEquals("-0,0000000001", NumbersTool.formatNumber(n4, 10, ','));
double n5 = 0.99999999999;
for (int i = 1; i <= 10; i++) {
assertEquals("0," + "9".repeat(i), NumbersTool.formatNumber(n5, i, ','));
}
double n6 = -0.99999999999;
for (int i = 1; i <= 10; i++) {
assertEquals("-0," + "9".repeat(i), NumbersTool.formatNumber(n6, i, ','));
}
double n7 = 0.99999999999999;
for (int i = 1; i <= 10; i++) {
assertEquals("0," + "9".repeat(i), NumbersTool.formatNumber(n7, i, ','));
}
double n8 = -0.99999999999999;
for (int i = 1; i <= 10; i++) {
assertEquals("-0," + "9".repeat(i), NumbersTool.formatNumber(n8, i, ','));
}
}
@Test
void formatNumber_7_edgeCaseRounding() {
double n = 2.675; // known floating point issue
assertEquals("2,6", NumbersTool.formatNumber(n, 1, ','));
assertEquals("2,67", NumbersTool.formatNumber(n, 2, ','));
assertEquals("2,675", NumbersTool.formatNumber(n, 3, ','));
assertEquals("2,6750", NumbersTool.formatNumber(n, 4, ','));
assertEquals("2,67500", NumbersTool.formatNumber(n, 5, ','));
assertEquals("2,675000", NumbersTool.formatNumber(n, 6, ','));
assertEquals("2,6750000", NumbersTool.formatNumber(n, 7, ','));
// fails at 8, 9, 10 due to floating point precision limits
assertEquals("2,67500000", NumbersTool.formatNumber(n, 8, ','));
assertEquals("2,675000000", NumbersTool.formatNumber(n, 9, ','));
assertEquals("2,6750000000", NumbersTool.formatNumber(n, 10, ','));
}
@Test
void formatNumber_8_edgeCaseBigNumbers() {
double n1 = 9999999999.0; // 10 nines before decimal point
for (int i = 1; i <= 8; i++) {
// fails at 9 and 10 due to floating point precision limits
assertEquals("9999999999," + "0".repeat(i), NumbersTool.formatNumber(n1, i, ','));
}
double n2 = -9999999999.0; // 10 nines before decimal point
for (int i = 1; i <= 8; i++) {
// fails at 9 and 10 due to floating point precision limits
assertEquals("-9999999999," + "0".repeat(i), NumbersTool.formatNumber(n2, i, ','));
}
}
}
Und es ist davon auszugehen, dass es auch noch mehr Randfälle geben könnte, dir mir gerade nicht einfielen.
Hint: Ich weiß selber, dass Schleifen in Unit-Tests eigentlich nicht zulässig sind... wollte aber euer Auge schonen.