Verschiedene Möglichkeiten, die Anzahl der Stellen einer Zahl zu berechnen

Als kleines Nebenthema hatte ich heute mit der Aufgabe zu tun, die Anzahl der Stellen einer Zahl (positive, ganze Zahl >=1) zu bestimmen. Mir fiel ein, dass ich das schonmal “irgendwie mit dem Logarithmus” gemacht habe.

Nach ein wenig Reflektieren und Googeln kamen folgende Lösungsmöglichkeiten in Betracht, jede für sich mit unterschiedlichen Ecken und Kanten. Da mein Problem “gelöst” ist (es ist an der geforderten Stelle völlig zeitunkritisch), stelle ich hier mal die verschiedenen Möglichkeiten rein akademisch zur Diskussion. Vielleicht gibt es ja auch noch mehr.


    public static void main(String[] args) {
        greetings();
        for (int i=1; i<101; ++i) {
            proof(i);
        }
        proof(101);
        proof(999);
        proof(1000);
        proof(1001);
        proof(9999);
        proof(10000);
        proof(10001);
        proof(99999);
        proof(100000);
        proof(100001);
        proof(999999);
        proof(1000000);
        proof(1000001);
        proof(9999999);
        proof(10000000);
        proof(10000001);
        proof(99999999);
        proof(100000000);
        proof(100000001);
        proof(999999999);
        proof(1000000000);
        proof(1000000001);
        proof(Integer.MAX_VALUE);
    }

    private static void greetings() {
        System.out.println("n	Log	Calc	If	String	Gleich");
    }

    private static void proof(int number) {
        int d1 = digitCountLog(number);
        int d2 = digitCountCalc(number);
        int d3 = digitCountIf(number);
        int d4 = digitCountString(number);
        boolean equal = d1 == d2 && d2 == d3 && d3 == d4;
        System.out.println(number + "	" + d1 + "	" + d2 + "	" + d3 + "	"
                + d4 + "	" + equal);
    }

    public static int digitCountLog(int input) {
        return ((int) Math.log10(input)) + 1;
    }

    public static int digitCountCalc(int input) {
        int digits = 1;
        while (input > 9) {
            input /= 10;
            ++digits;
        }
        return digits;
    }

    public static int digitCountIf(int input) {
        if (input < 100000) {
            if (input < 1000) {
                if (input < 100) {
                    if (input < 10) {
                        return 1;
                    }
                    return 2;
                }
                return 3;
            }
            if (input < 10000) {
                return 4;
            }
            else {
                return 5;
            }
        }
        if (input < 100000000) {
            if (input < 10000000) {
                if (input < 1000000) {
                    return 6;
                }
                return 7;
            }
            return 8;
        }
        if (input < 1000000000) {
            return 9;
        }
        else {
            return 10;
        }
    }

    public static int digitCountString(int input) {
        return Integer.toString(input).length();
    }

}

gibt es für den kompliziert verschachtelten digitCountIf-Aufbau eine besondere Ursache bei dir, die hier nicht erwähnt ist und allgemein auch unerheblich wäre? :wink:
die anderen drei sind immerhin auch optimal kurz gebaut,

digitCountIf könnte künstlerisch schöner, übersichtlicher und damit sicherer auch

        if (input < 10) return 1;
        if (input < 100) return 2;
        if (input < 1000) return 3;
        if (input < 10000) return 4;
        if (input < 100000) return 5;
        if (input < 1000000) return 6;
        if (input < 10000000) return 7;
        if (input < 100000000) return 8;
        if (input < 1000000000) return 9;
        return 10;
    }
```sein

negative Werte natürlich immer ein Problem

rekursive Lösung (dein digitCountCalc umschreiben) wäre doch viel schöner

Der stammt aus einem Mikrocontroller-Forum. Ich habe ihn dann nicht weiter angefasst, als er funktionierte. Mag sein, dass es auf dieser Ebene Vorteile für bestimmte Mikroprozessoren in dieser Form gibt.

Die aufgeräumtere Variante sieht auf jeden Fall sehr viel übersichtlicher aus.

Ach ja, rekursiv geht das natürlich auch noch.

ist bestimmt versuchte Optimierung durch Intervallhalbierung,
das erste if teilt 5 Fälle zu 5 Fälle, danach 3er und 2er

annähernd gleich viele aus jedem Bereich ist kühn vermutet bei unterschiedlich großen Bereichen,
für Zufallszahlen dürften 99% mindestens 8 Stellen haben, ifs in Reihenfolge von oben her günstiger,
falls im normalen Bereich eher kleine Zahlen, könnte es von unten anfangen

Mal so ungetestet aus’m Handgelenk:

public static int digitCountIf(int input) {
  int len = 1;
  while(input >= 10) {
     input /= 10;
     len++;
  }
  return len;
}

steht doch schon da (digitCountCalc) :wink:
zur Strafe nun noch die geforderte rekursive Variante

Na die ist trivial:

public static int digitCountRec(int input) {
   return input < 10 ? 1 : 1 + digitCountRec(input / 10);
}

Ne ähnliche Frage war schonmal woanders, da ging es um Performance, und die Lösung, die SlaterB als erstes genannt hatte, war AFAIK die schnellste (und damals hatte sie AFAIK Landei vorgeschlagen, aber da bin ich nicht sicher… laaange her)

Nur mal so als idee, wobei das wahrscheinlich extrem langsam ist:

		long powResult = (long) (long) Math.pow(10, level);
		long rest = l % powResult;
		boolean existing = rest < l;
//		System.out.println("l: " + level + ", r: " + rest + ", pr: " + powResult + ", ex: " + existing);
		return existing ? 1 + calcDigitCount(l, level + 1) : 1;
	}```

@mymaksimus : abgesehen von der Performance (habe ich nicht getestet) finde ich den Code aber vor allem unverständlich.

uhm. ja. find ich auch. :smiley:

naja ich vergleiche immer den rest von input / 10^level, level steht quasi für die stelle.
wenn dieser rest < input ist, dann existiert die level-te stelle.

Das ganze wird noch unperformanter, wenn man zur mitbetrachtung der minuszahlen
noch math.abs einbaut ^^

War halt nur ne idee.
Aber im anwendungsfall würde ich wohl auf String.valueOf(input).length() zurückgreifen, wäre für mich
am leserlichsten. die performance wäre aber wohl scheiße.

Sry, ich weiß nicht, ob es schon genannt wurde oder auf mikro controller zur Verfügung steht,
return (int) Math.ceil(Math.log(Math.abs(x))/Math.log(10));
Auf Handy ich nicht testen kann und ich nicht Mathe -Experte bin.

[quote=mymaksimus]Aber im anwendungsfall würde ich wohl auf String.valueOf(input).length() zurückgreifen, wäre für mich
am leserlichsten. die performance wäre aber wohl scheiße.[/quote]

So hab ich es gemacht, weil ich die Rechnung nur einmal am Anfang nach einer Benutzerangabe machen muss, und an der Stelle die Performance wumpe ist.