Java / Kotlin: Berechnen Sie den Quotienten, indem Sie die Anzahl der gültigen Zahlen angeben, wenn er nicht durch die Division (Division) von BigDecimal teilbar ist.

Wenn es teilbar ist, berechnen Sie bitte bis zu dem Punkt, an dem es teilbar ist. Wenn es jedoch nicht teilbar ist, suchen Sie immer den Quotienten mit der gleichen Anzahl gültiger Ziffern. Ich denke, es wird für eine Anwendung notwendig sein, die das Berechnungsergebnis der Division wie einen Taschenrechner anzeigt. Ich konnte im Netz keinen guten Weg finden, also habe ich selbst darüber nachgedacht (`・ ω ・ ´)

(Hinzugefügt am 16.07.2018) Ich habe unten in GIF ein Anwendungsbeispiel hinzugefügt, um zu verdeutlichen, was ich erreichen möchte. Dieses Bild wurde übrigens mit einer von mir entwickelten Taschenrechner-App namens Calc Leaf aufgenommen.

Selbst wenn die Antwort eine unendliche Zahl ist, besteht der Zweck darin, sie innerhalb des anzeigbaren Bereichs korrekt anzuzeigen.

Für Java

Hier sind einige Ausgabebeispiele. Ich werde es hier weglassen, aber wenn Sie die erhaltene Antwort mit "Dezimalformat" formatieren, sieht die Anzeige gut aus.

Division.java


import java.math.BigDecimal;
import java.math.RoundingMode;

public class Division {
	
	public static final int SIGNIFICANT_DIGITS = 3; //Anzahl gültiger Ziffern
	
	public static void main(String[] args) {
		try {
			System.out.println(divided("10000", "3")); // 3330
			System.out.println(divided("1000", "3"));  // 333
			System.out.println(divided("100", "3"));   // 33.3
			System.out.println(divided("10", "3"));    // 3.33
			System.out.println(divided("1", "3"));     // 0.333
			System.out.println(divided("1", "30"));    // 0.0333
			System.out.println(divided("1", "300"));   // 0.00333
			System.out.println(divided("1", "3000"));  // 0.000333
			System.out.println(divided("1", "30000")); // 0.0000333
		} catch(NumberFormatException nfe) {
			System.out.println("Error: Not a number.");
		} catch(ArithmeticException ae) {
			System.out.println("Error: Impossible to calculate.");
		} catch(Exception e) {
			System.out.println("Error: Unexpected.");
		}
	}

	public static String divided(String dividend, String divisor) throws Exception {
		BigDecimal bdDividend = new BigDecimal(dividend);
		BigDecimal bdDivisor = new BigDecimal(divisor);
		BigDecimal answer = null;
		
		try {
			//Wenn es teilbar ist, teilen Sie es so wie es ist
			answer = bdDividend.divide(bdDivisor);
		} catch(ArithmeticException arithmeticException) {
			//Wenn es nicht teilbar ist, berechnen Sie eine gültige Skala (in diesem Beispiel wird die Rundung gerundet).
			answer = bdDividend.divide(bdDivisor, getSignificantScale(bdDividend, bdDivisor), RoundingMode.HALF_UP);
		}
		return answer.stripTrailingZeros().toPlainString();
	}
	
	public static int getSignificantScale(BigDecimal dividend, BigDecimal divisor) {
		//Absolutwert ohne nachgestellte Nullen nach dem Dezimalpunkt
		BigDecimal bd1 = dividend.abs().stripTrailingZeros();
		BigDecimal bd2 = divisor.abs().stripTrailingZeros();
		//Konvertieren Sie in natürliche Zeichenfolgen gemäß natürlichen Zahlen
		int decimalDigits = bd1.scale() > bd2.scale() ? bd1.scale() : bd2.scale();
		if (decimalDigits < 0) decimalDigits = 0;
		String s1 = bd1.scaleByPowerOfTen(decimalDigits).toPlainString();
		String s2 = bd2.scaleByPowerOfTen(decimalDigits).toPlainString();
		//Berechnen Sie eine gültige Skala und geben Sie sie zurück
		return SIGNIFICANT_DIGITS - (s1.length() - s2.length()) - (s1.compareTo(s2) >= 0 ? 1 : 0);
	}
}

Für Kotlin

Sie können es kopieren und in Try kotlin einfügen. Sie können "let" verwenden, um "val" in einer Zeile zu erstellen, in der Sie "decimalDigits" möchten, aber ich habe es gestoppt, weil es subtil ist.

Division.kt


import java.math.BigDecimal
import java.math.RoundingMode

const val SIGNIFICANT_DIGITS: Int = 3 //Anzahl gültiger Ziffern

fun main(args: Array<String>) {
    try {
    	println(divided("10000", "3")) // 3330
    	println(divided("1000", "3"))  // 333
    	println(divided("100", "3"))   // 33.3
    	println(divided("10", "3"))    // 3.33
    	println(divided("1", "3"))     // 0.333
    	println(divided("1", "30"))    // 0.0333
    	println(divided("1", "300"))   // 0.00333
    	println(divided("1", "3000"))  // 0.000333
    	println(divided("1", "30000")) // 0.0000333
    } catch(nfe: NumberFormatException) {
        println("Error: Not a number.")
    } catch(ae: ArithmeticException) {
        println("Error: Impossible to calculate.")
    } catch(e: Exception) {
        println("Error: Unexpected.")
    }
}

fun divided(dividend: String, divisor: String): String {
    val bdDividend = BigDecimal(dividend)
    val bdDivisor = BigDecimal(divisor)
    val answer = try {
        //Wenn es teilbar ist, teilen Sie es so wie es ist
        bdDividend.divide(bdDivisor)
    } catch(ae: ArithmeticException) {
        //Wenn es nicht teilbar ist, berechnen Sie eine gültige Skala (in diesem Beispiel wird die Rundung gerundet).
        bdDividend.divide(bdDivisor, getSignificantScale(bdDividend, bdDivisor), RoundingMode.HALF_UP)
    }
    return answer.stripTrailingZeros().toPlainString()
}

fun getSignificantScale(dividend: BigDecimal, divisor: BigDecimal): Int {
    //Absolutwert ohne nachgestellte Nullen nach dem Dezimalpunkt
    val bd1 = dividend.abs().stripTrailingZeros()
    val bd2 = divisor.abs().stripTrailingZeros()
    //Konvertieren Sie in natürliche Zeichenfolgen gemäß natürlichen Zahlen
    var decimalDigits = if (bd1.scale() > bd2.scale()) bd1.scale() else bd2.scale()
    if (decimalDigits < 0) decimalDigits = 0
    val s1 = bd1.scaleByPowerOfTen(decimalDigits).toPlainString()
    val s2 = bd2.scaleByPowerOfTen(decimalDigits).toPlainString()
    //Berechnen Sie eine gültige Skala und geben Sie sie zurück
    return SIGNIFICANT_DIGITS - (s1.length - s2.length) - (if (s1 >= s2) 1 else 0)
}

Bitte verwenden Sie auf eigenes Risiko

Sie können den obigen Code selbst testen und nach Belieben verwenden. Der von mir durchgeführte Testcode wurde auf ~~ github hochgeladen (veröffentlicht als Antwort auf Kommentare von kaizen_nagoya). Wir haben ungefähr 50 Muster basierend auf der Beziehung zwischen der zu teilenden Zahl und der zu teilenden Zahl, der Position des Dezimalpunkts, positiv / negativ und ob es sich um eine Exponentialschreibweise handelt oder nicht, überprüft und die Anforderungen geklärt. Es ist jedoch nicht zu leugnen, dass es an Objektivität mangelt, weil ich es alleine gemacht habe (´ ・ ω ・ `) Also, diejenigen, die überprüfen und erneut verifizieren, sind willkommen! Wenn Sie Informationen zu Bibliotheken oder Referenzseiten haben, die dasselbe tun, würde ich mich sehr freuen, wenn Sie mich darüber informieren könnten! (Ich habe jetzt darüber nachgedacht, aber es kann im mathematischen Wörterbuch aufgeführt sein. Ich habe es nicht.)

Sie können es unter Berücksichtigung der Anzeige des Berechnungsergebnisses anpassen.

getSignificantScale wird tatsächlich in meiner entwickelten Taschenrechner-App CalcLeaf verwendet, ist aber tatsächlich ein wenig Es gibt einen Unterschied in der Implementierung. Der Punkt ist, dass "0 zurückgegeben wird, wenn das Berechnungsergebnis einer gültigen Skala negativ ist", wie unten gezeigt.

Sample.java


int significantScale = SIGNIFICANT_DIGITS - (s1.length() - s2.length()) - (s1.compareTo(s2) >= 0 ? 1 : 0);
return significantScale < 0 ? 0 : significantScale;

Im Fall eines Taschenrechners ist es beispielsweise unangenehm, wenn die Antwort von 1.000.000.000.000 ÷ 3 333.333.333.330 lautet, und Calc Leaf hat sie als Spezifikation angepasst.

Impressionen

Ich wünschte, ich könnte es standardmäßig mit Java API tun. Ich frage mich, ob Leute in Java darüber nachdenken werden, wenn sie es sehen.

Recommended Posts

Java / Kotlin: Berechnen Sie den Quotienten, indem Sie die Anzahl der gültigen Zahlen angeben, wenn er nicht durch die Division (Division) von BigDecimal teilbar ist.
[Java] Tag ab Datum berechnen (Kalenderklasse nicht verwenden)
Bitte beachten Sie die Aufteilung (Aufteilung) von Java Kotlin Int und Int
Die Idee, abzuschalten, wenn der Fehler nicht behoben ist
Zählen Sie die Anzahl der Stellen nach dem Dezimalpunkt in Java
[Schienen] Wenn die Layoutänderung des Geräts nicht berücksichtigt wird
Wechseln Sie die von SDKMAN installierte Java-Version, wenn Sie Verzeichnisse verschieben
Untersuchungsmethode, wenn die CPU des Servers, auf dem Java ausgeführt wird, schwer ist