diff --git a/src/main/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumber.kt b/src/main/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumber.kt index 6aebccbaa..13827a18a 100644 --- a/src/main/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumber.kt +++ b/src/main/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumber.kt @@ -1,5 +1,6 @@ package ch.kleis.lcaplugin.ui.toolwindow +import arrow.core.flatten import arrow.core.replicate import com.intellij.util.containers.tail import kotlin.math.* @@ -15,7 +16,10 @@ class DisplayedNumber( init { fun prepareNonZero(v: Double): Pair> { val w = abs(v) - val positionalExponent = ceil(log10(w)).toInt() + val e = ceil(log10(w)).toInt() + val positionalExponent = + if (w == 10.0.pow(e)) e + else e - 1 val shift = nbSignificantDigits - positionalExponent val reversedDigits = ArrayList() var u = floor(w * (10.0.pow(shift))).toInt() @@ -23,13 +27,13 @@ class DisplayedNumber( reversedDigits.add(u.mod(10)) u /= 10 } - val digits = reversedDigits.reversed() + val digits = reversedDigits.reversed().take(nbSignificantDigits) if (digits.tail().take(nbSignificantDigits - 1).all { it == 9 }) { val hd = digits[0] if (hd == 9) { val zeros = listOf(0).replicate(nbSignificantDigits - 2).flatten() - return positionalExponent to listOf(1, 0) + zeros + return positionalExponent + 1 to listOf(1, 0) + zeros } val zeros = listOf(0).replicate(nbSignificantDigits - 1).flatten() return positionalExponent to listOf(hd + 1) + zeros @@ -40,7 +44,7 @@ class DisplayedNumber( if (value == 0.0) { isPositive = true - positionalExponent = 1 + positionalExponent = 0 digits = IntRange(1, nbSignificantDigits).map { 0 } } else { val (e, d) = prepareNonZero(value) @@ -50,7 +54,7 @@ class DisplayedNumber( } } - fun getExponent(): Int { + fun getPositionalExponent(): Int { return positionalExponent } @@ -77,43 +81,40 @@ class DisplayedNumber( } override fun toString(): String { - if (value == 0.0) { - return "0" - } - - if (isPowerOf10()) { - return renderPowerOf10() - } - - val midpoint = when { - positionalExponent <= -nbSignificantDigits + 1 -> 1 - -nbSignificantDigits + 1 < positionalExponent - && positionalExponent < nbSignificantDigits -> positionalExponent - - else -> nbSignificantDigits - } - val displayedExponent = when { - -nbSignificantDigits + 1 < positionalExponent - && positionalExponent < nbSignificantDigits -> 0 - - else -> positionalExponent - midpoint - } - - val head = when { - midpoint <= 0 -> emptyList() - else -> digits.subList(0, midpoint) - }.joinToString("").ifEmpty { "0" } - val tail = when { - midpoint <= 0 -> { - val prefix = listOf(0).replicate(-midpoint).flatten() - prefix + digits.take(nbSignificantDigits) + return when { + positionalExponent in -2 .. -1 -> { + val hd = listOf(0).replicate(-positionalExponent-1).flatten() + .joinToString("") + .let { "0.$it" } + val tl = digits.take(nbSignificantDigits - positionalExponent + 1) + .dropLastWhile { it == 0 } + .joinToString("") + val sign = if (isPositive) "" else "-" + "$sign$hd$tl" } - else -> digits.subList(midpoint, nbSignificantDigits) - }.dropLastWhile { it == 0 }.joinToString("") - - val sign = if (isPositive) "" else "-" - val e = if (displayedExponent == 0) "" else "E$displayedExponent" - return if (tail.isEmpty()) "$sign$head$e" else "$sign${head}.$tail$e" + positionalExponent in 0..2 -> { + val midpoint = min(positionalExponent + 1, nbSignificantDigits) + val hd = digits.subList(0, midpoint) + .joinToString("") + val tl = digits.subList(midpoint, nbSignificantDigits) + .dropLastWhile { it == 0 } + .joinToString("") + .let { if (it.isEmpty()) "" else ".$it"} + val sign = if (isPositive) "" else "-" + "$sign$hd$tl" + } + else -> { + val hd = digits.subList(0, 1) + .joinToString("") + val tl = digits.subList(1, nbSignificantDigits) + .dropLastWhile { it == 0 } + .joinToString("") + .let { if (it.isEmpty()) "" else ".$it"} + val sign = if (isPositive) "" else "-" + val e = "E$positionalExponent" + "$sign$hd$tl$e" + } + } } } diff --git a/src/test/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumberTest.kt b/src/test/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumberTest.kt index 85e6a1c41..d240c9905 100644 --- a/src/test/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumberTest.kt +++ b/src/test/kotlin/ch/kleis/lcaplugin/ui/toolwindow/DisplayedNumberTest.kt @@ -5,16 +5,119 @@ import kotlin.test.assertEquals class DisplayedNumberTest { @Test - fun test_displayedNumber() { - // given - val value = 1.2345 + fun test_positive_displayedNumber() { + listOf( + 0.0012345 to -3 to "123", + 0.012345 to -2 to "123", + 0.12345 to -1 to "123", + 1.2345 to 0 to "123", + 12.345 to 1 to "123", + 123.45 to 2 to "123", + 1234.5 to 3 to "123", + 12345.0 to 4 to "123", + + 0.0 to 0 to "000", + 0.0001 to -4 to "100", + 0.001 to -3 to "100", + 0.01 to -2 to "100", + 0.1 to -1 to "100", + 1.0 to 0 to "100", + 10.0 to 1 to "100", + 100.0 to 2 to "100", + 1000.0 to 3 to "100", + + 0.000999 to -3 to "100", + 0.00999 to -2 to "100", + 0.0999 to -1 to "100", + 0.999 to 0 to "100", + 9.99 to 1 to "100", + 99.9 to 2 to "100", + 999.0 to 3 to "100", + + 0.001001 to -3 to "100", + 0.01001 to -2 to "100", + 0.1001 to -1 to "100", + 1.001 to 0 to "100", + 10.01 to 1 to "100", + 100.1 to 2 to "100", + 1001.0 to 3 to "100", + + 0.0002999 to -4 to "300", + 0.003999 to -3 to "400", + 0.04999 to -2 to "500", + 0.5999 to -1 to "600", + 6.999 to 0 to "700", + 79.90 to 1 to "800", + 899.9 to 2 to "900", + ).forEach { + val value = it.first.first + val expectedPositionalExponent = it.first.second + val expectedDigits = it.second + + val actual = DisplayedNumber(value) + val actualPositionalExponent = actual.getPositionalExponent() + val actualDigits = actual.getDigits().joinToString("") + + assertEquals(expectedPositionalExponent to expectedDigits, actualPositionalExponent to actualDigits, "value = $value") + } + } - // when - val actual = DisplayedNumber(value, nbSignificantDigits = 3) + @Test + fun test_negative_displayedNumber() { + listOf( + 0.0012345 to -3 to "123", + 0.012345 to -2 to "123", + 0.12345 to -1 to "123", + 1.2345 to 0 to "123", + 12.345 to 1 to "123", + 123.45 to 2 to "123", + 1234.5 to 3 to "123", + 12345.0 to 4 to "123", + + 0.0 to 0 to "000", + 0.0001 to -4 to "100", + 0.001 to -3 to "100", + 0.01 to -2 to "100", + 0.1 to -1 to "100", + 1.0 to 0 to "100", + 10.0 to 1 to "100", + 100.0 to 2 to "100", + 1000.0 to 3 to "100", + + 0.000999 to -3 to "100", + 0.00999 to -2 to "100", + 0.0999 to -1 to "100", + 0.999 to 0 to "100", + 9.99 to 1 to "100", + 99.9 to 2 to "100", + 999.0 to 3 to "100", + + 0.001001 to -3 to "100", + 0.01001 to -2 to "100", + 0.1001 to -1 to "100", + 1.001 to 0 to "100", + 10.01 to 1 to "100", + 100.1 to 2 to "100", + 1001.0 to 3 to "100", - // then - assertEquals(1, actual.getExponent()) - assertEquals(listOf(1, 2, 3), actual.getDigits()) + 0.0002999 to -4 to "300", + 0.003999 to -3 to "400", + 0.04999 to -2 to "500", + 0.5999 to -1 to "600", + 6.999 to 0 to "700", + 79.90 to 1 to "800", + 899.9 to 2 to "900", + ).forEach { + val value = -it.first.first + val expectedPositionalExponent = it.first.second + val expectedDigits = it.second + + val actual = DisplayedNumber(value) + val actualPositionalExponent = actual.getPositionalExponent() + val actualDigits = actual.getDigits().joinToString("") + + assertEquals(expectedPositionalExponent to expectedDigits, actualPositionalExponent to actualDigits, "value = $value") + } } @Test @@ -37,6 +140,14 @@ class DisplayedNumberTest { 99.9 to "100", 999.0 to "1E3", + 0.001001 to "1E-3", + 0.01001 to "0.01", + 0.1001 to "0.1", + 1.001 to "1", + 10.01 to "10", + 100.1 to "100", + 1001.0 to "1E3", + 0.003999 to "4E-3", 0.04999 to "0.05", 0.5999 to "0.6", @@ -49,7 +160,10 @@ class DisplayedNumberTest { 0.0123 to "0.0123", 0.123 to "0.123", 1.2345 to "1.23", - 12345.123 to "123E2", + 12.345 to "12.3", + 123.45 to "123", + 1234.5 to "1.23E3", + 12345.123 to "1.23E4", -0.0 to "0", -0.0001 to "-1E-4", @@ -63,7 +177,7 @@ class DisplayedNumberTest { -0.0123 to "-0.0123", -0.123 to "-0.123", -1.2345 to "-1.23", - -12345.123 to "-123E2", + -12345.123 to "-1.23E4", -0.00123 to "-1.23E-3", ).forEach { val actual = DisplayedNumber(it.first).toString()