Nicht lineare "progressbar" % berechnen

machhommy schrieb:
Folgende Formel funktioniert z.B. ziemlich gut aber ist eben mMn nicht so leicht zu pflegen.
Sie funktioniert vor allem, weil du durch Zufall passende Punkte gefunden hast.
Mit anderen Punkten funktioniert das mit dem Polynom nicht mehr so gut:
Screenshot 2022-06-09 165601.png

Die Lösung von @tollertyp setzt auf eine lineare Interpolation zwischen den Punkte, damit ist die Funktion nicht mehr stetig, aber dank der eleganten Umsetzung leicht anzupassen.
 
  • Gefällt mir
Reaktionen: tollertyp und CyborgBeta
CyborgBeta schrieb:
Welcher Beitrag denn genau?

Du musst auch nicht genau sagen, was das Problem ist, aber dann lass mich in Ruhe.
Sorry, aber die im Eingangsposting gezeigte Progress-Bar ist jedenfalls unlogisch, weil sie Werte kleiner 0 und größer 100 annehmen kann.
 
CyborgBeta schrieb:
Welcher Beitrag denn genau?

Du musst auch nicht genau sagen, was das Problem ist, aber dann lass mich in Ruhe.

Junge was ist dein Problem? Ich habe dir explizit für deinen Einsatz und Bemühungen hier gedankt und dich nett drauf hingewiesen das du vermutlich das Problem nicht richtig verstanden hast, was überhaupt nicht schlimm, da es eben nichts "alltägliches" ist. Statt nun etwas Eigeninitiative zu zeigen und versuchen das Problem zu verstehen, wirst du trotzig wie ein kleines Kind ...

CyborgBeta schrieb:
Sorry, aber die im Eingangsposting gezeigte Progress-Bar ist jedenfalls unlogisch, weil sie Werte kleiner 0 und größer 100 annehmen kann.

Auch das ist falsch bzw. die Skizze ist richtig, was hier auch schon mehrmals bestätigt wurde und es kann auch kein Wert kleiner als 0 existieren. Vorher war es nur eine Vermutung aber nun ist es Gewissheit. Du hast das Problem nicht verstanden.
 
  • Gefällt mir
Reaktionen: KitKat::new()
Nilson schrieb:
Mit anderen Punkten funktioniert das mit dem Polynom nicht mehr so gut:
Kann man mit einem höherem Grad und mehr Punkten fixen ;)
 
@machhommy Du musst nicht beleidigend werden.

Damit das hier mal ein Ende findet:

Javascript:
let milestones = [10, 30, 20];

function getPercent(milestoneIndex, milestoneValue) {
  let sum = 0;
  for (let i = 0; i < milestoneIndex; i++) {
    sum += milestones[i];
  }
  sum += milestoneValue;
  let sum2 = milestones.reduce((a, b) => a + b, 0);
  return sum / sum2 * 100.0;
}

for (let i = 0; i <= 10; i++) {
  console.log(i + " of 1/3 is " + getPercent(0, i));
}
for (let i = 0; i <= 30; i++) {
  console.log(i + " of 2/3 is " + getPercent(1, i));
}
for (let i = 0; i <= 20; i++) {
  console.log(i + " of 3/3 is " + getPercent(2, i));
}
 
CyborgBeta schrieb:
@machhommy Du musst nicht beleidigend werden.

:confused_alt:
Ergänzung ()

KitKat::new() schrieb:
Kann man mit einem höherem Grad und mehr Punkten fixen ;)

Da wären wir dann bei ...
machhommy schrieb:
Ich bin mir auch ziemlicher sich das man die Formeln weiter anpassen kann

Dafür bin ich aber zu wenig Mathematiker. Kann mir aber sehr gut vorstellen das viele das Problem eben mit einer entsprechend (angepassten) Formel lösen würden. Ich will aber nur effektiv nach Rom kommen, dafür muss ich kein Rad extra zusammenbauen wenn mich mein Scooter nehmen kann :)
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: tollertyp und CyborgBeta
Eben, ich bin dann auch auf der Suche nach einer pragmatischen Lösung, die dann auch von quasi jedem gewartet (konfiguriert) angepasst werden kann. Ja, natürlich auch nicht von jedem.

@CyborgBeta: Irgendwie passt deine finale Lösung dennoch nicht zur Ausgangsaufgabenstellung, vielleicht ist das beabsichtigt, oder ich irre ich und bin zu blöd dafür es richtig zu erkennen.
 
tollertyp schrieb:
Irgendwie passt deine finale Lösung dennoch nicht zur Ausgangsaufgabenstellung
Meiner Ansicht nach passt es schon, ich wüsste nicht, wie es sonst anders gehen sollte. Aber zu 100% sicher bin ich mir nicht. @machhommy kann das ja einfach einmal testen.
 
hm, das müsste passen:

Javascript:
let milestones = [10, 30, 20];

function getPercentFromMilestone(milestoneIndex, milestoneValue) {
  let sum = 0;
  for (let i = 0; i < milestoneIndex; i++) {
    sum += milestones[i];
  }
  sum += milestoneValue;
  let sum2 = milestones.reduce((a, b) => a + b, 0);
  return sum / sum2 * 100.0;
}

function getPercent(val) {
  let sum = milestones.reduce((a, b) => a + b, 0);
  return val / sum * 100.0;
}

function getMilestone(val) {
  for (let i = 0; i < milestones.length; i++) {
    val -= milestones[i];
    if (val <= 0) {
      return i;
    }
  }
  return -1;
}

for (let i = 0; i <= 30; i++) {
  console.log(i + " of MS 2 is " + getPercentFromMilestone(1, i) + " %");
}

for (let i = 0; i <= 60; i++) {
  console.log(i + " of all MS is " + getPercent(i) + " %, that is MS " + (getMilestone(i) + 1));
}

https://jsfiddle.net/4yfc9a27/ zum Ausprobieren
 
Ich war mal so frei, deinen Code auf das wesentliche (die Funktion getPercent) zu reduzieren:
Code:
let milestones = [20, 30, 10];

function getPercent(val) {
  let sum = milestones.reduce((a, b) => a + b, 0);
  return val / sum * 100.0;
}

for (let i = 0; i <= 60; i++) {
  console.log(i, getPercent(i));
}
So und die Funktion getPercent macht eben nicht genau das, was sie machen soll. Sie gewichtet eben nicht die Punkte abhängig vom Meilenstein unabhängig stark. Wo kann der TE denn festlegen, bei wievielen Punkten der Meilenstein 1 liegt und wieviel Prozent das entspricht?

Bei dir könnte ich auch einfach optimieren, weil es eh komplett linear ist:
Code:
function getPercent(val) {
  return (100/60) * val * 100.0;
}

Ich bekomme den Eindruck, dass dir die Aufgabenstellung, die im ersten Post ehrlich gesagt vollständig, wenn auch vielleicht nicht auf Anhieb super verständlich, nach wie vor nicht bewusst ist. Wie erreiche ich mit dieser Funktion (also wie könnte ein milestones-Array aussehen dafür), dass der Eingangswert i=20 z.B. 17% liefert, i=50 dann 50% und i=100 schließlich 83%?

Ja, die Funktion getPercentFromMilestone( mag gewichten, aber das ist halt nicht das, wonach der TE gefragt hat. Klar, kann er damit arbeiten, und anfangen dann diese Ergebnisse wieder umzurechnen, aber dann sind Dinge, die eigentlich zusammen gehören wieder irgendwie verteilt.

Ich poste erneut meine "naive" Lösung, diesmal sogar um eine fehlende Zeile ergänzt (dachte, ich hätte sie reineditiert), und auch als Funktion:
Code:
var milestones = {};
milestones[0] = 0;
milestones[20] = 17;
milestones[50] = 50;
milestones[100] = 83;

function getPercent(p) {
  var lowerBounds = 0;
  var higherBounds = 0;
  for (var key in milestones) {
      if (p < higherBounds) {
          break;
      }
      lowerBounds = higherBounds;
      higherBounds = key;
  }
  var lowerPercentage = milestones[lowerBounds];
  var higherPercentage = milestones[higherBounds];
  var percent = lowerPercentage + (higherPercentage - lowerPercentage) * (p - lowerBounds) / (higherBounds - lowerBounds)
  return percent;
}

for (let i = 0; i <= 100; i++) {
  console.log(i,  getPercent(i));
}
Mag eleganter gehen in JS, und letztendlich ist es mir relativ egal, ob man die Meilensteine absolut (wie in meinem Fall) oder relativ definiert, das würde ich vom Nutzungsszenario abhängig machen. Man muss sich fragen: Soll das Erhöhen der Hürde zum Erreichen von einem Meilenstein sich auf andere Meilensteine auswirken? Wenn ja, dann ist es sicher besser, die Grenzen relativ zu definieren. Wenn nein, dann sind wohl absolute Werte besser. Ich habe mich für absolut entschieden, weil ich den Eindruck hatte, dass die Meilenstein-Hürden eher unabhängig sind.
 
Zuletzt bearbeitet: (So, musste den Beitrag nochmal grundlegend aktualisieren.)
Du hast die Funktion einfach umgedreht, oder? Statt von Punkten (Milestone) zu Prozent (Fortschritt) zeigt sie nun von Prozent (Fortschritt) zu Punkten (Milestone). Dann ist der Name getPercent falsch.

Könnte sein, dass das gesucht ist, könnte aber auch nicht sein...
Ergänzung ()

Ja, es geht vielleicht einfacher:

Javascript:
let milestones = [10, 30, 20];
let milestonesSum = milestones.reduce((a, b) => a + b, 0);

function getPercentFromValue(val) {
  return val / milestonesSum * 100.0;
}

function getValueFromPercent(per) {
  return per / 100.0 * milestonesSum;
}

function getMilestoneIndexFromPercent(per) {
  let v = getValueFromPercent(per);
  let i = 0;
  while (i < milestones.length && v > milestones[i]) {
    v -= milestones[i];
    i++;
  }
  return i;
}

console.log("percent to value :");
for (let i = 0; i <= 100; i++) {
  console.log(i, getValueFromPercent(i), getMilestoneIndexFromPercent(i));
}
console.log("value to percent :");
for (let i = 0; i <= milestonesSum; i++) {
  console.log(i, getPercentFromValue(i), getMilestoneIndexFromPercent(getPercentFromValue(i)));
}

https://jsfiddle.net/gepojrhL/

Eben simple Prozentrechnung...
 
Zuletzt bearbeitet:
Moin. Noch mal drüber nachgedacht. Damit man weiß, wo die Markierungen gesetzt werden sollen, würde ich verwenden:

Javascript:
function getRange(milestoneIndex) {
  let a = getPercentFromValue(milestones[milestoneIndex]);
  let b = 0;
  Array(milestoneIndex + 1).fill(0).map((_, i) => i).forEach(i => b += getPercentFromValue(milestones[i]));
  return [Math.round(b - a), Math.round(b)];
}

console.log("Range :");
for (let i = 0; i < milestones.length; i++) {
  console.log(i, getRange(i));
}

Das Array(milestoneIndex + 1)... ist nur eine "Kurz"schreibweise für:

Javascript:
function getRange(milestoneIndex) {
  let a = getPercentFromValue(milestones[milestoneIndex]);
  let b = 0;
  for (let i = 0; i <= milestoneIndex; i++) {
    b += getPercentFromValue(milestones[i]);
  }
  return [Math.round(b - a), Math.round(b)];
}

Ich finde die zweite Variante wesentlich angenehmer zu lesen, aber manche stehen auf funktionale Programmierung...

Hier wieder das komplette Fiddle: https://jsfiddle.net/s2L49u0x/
 
So viel Text von mir, da muss die Frage untergegangen sein. Ich wiederhole sie gerne:
tollertyp schrieb:
Wie erreiche ich mit dieser Funktion (also wie könnte ein milestones-Array aussehen dafür), dass der Eingangswert i=20 z.B. 17% liefert, i=50 dann 50% und i=100 schließlich 83%?
Also falls du dich über die Zahlen wunderst, einfach mal den Eröffnungspost anschauen. Ich bin so freundlich und mache einen Screenshot:
1654882744801.png

Und nochmals als Erinnerung: Nein, die Punkte sind eigentlich nicht sichtbar für den Nutzer.

Weil nur mal so am Rande: Das ist die Aufgabe. Falls du irgendeine persönliche Programmier-Challenge hast, kein Problem, tobe dich aus: Ich sehe nur keinen Zusammenhang zum Thread.
 
  • Gefällt mir
Reaktionen: KitKat::new()
Ich habe auch einen kurzen Blick auf das Problem geworfen und würde das Problem, bei den Informationen die uns zur Verfügung stehen, mittels linearer Interpolation lösen.

Der Vorteil der linearen Interpolation ist, dass du eine Funktion erhälst, die monoton steigend und stetig ist.
Bei deinen vorgegeben Werten erhalten wir folgende Funktion. Da irgendwann die 100 % erreicht werden sollen, habe ich beispielsweise den Punkt (130 | 100) hinzugefügt. Diese Funktion ist auf ganz ℝ definiert und bildet auf das Intervall [0; 100] ab.

F: ℝ ⟶ [0; 100]


06.png



Hier noch ein jsfiddle.
 
Die Formel
Code:
var percent = (yUpperBound - yLowerBound) / (xUpperBound - xLowerBound) * (x - xLowerBound) + yLowerBound;
kommt mir echt bekannt vor.
Code:
var percent = lowerPercentage + (higherPercentage - lowerPercentage) * (p - lowerBounds) / (higherBounds - lowerBounds);
 
Die englischen bezeichnungen für Schranken.

x_0 und x_1 bzw. y_0 und y_1 wären nicht sauber und xInf und xSup bzw. yInf und ySup sind eher irritierend.




Warum die Formel bekannt vorkommt?
Weil das die Definition einer linearen Funktion
01.png
.

Wobei k die Steigung der Geraden zwischen zwei Punkten ist, welche mit dem Differenzenquotienten berechnet wird.
02.png


Wir suchen Funktionen der folgenden Form:
03.png


k ist die Steigung, mit (x - a) wird die Funktion an die Stelle a verschoben und f(a) hebt die Funktion an der Stelle a so, dass diese dort den gewünschten Wert hat.

Wir erhalten für die Punkte (0 | 0) ; (20 | 17); (50 | 50); (100 | 83); (130 |100) folgende Funktionen.

04.png


aus diesen Funktionen definieren wir die abschnittsweise definierte Funktion F.

05.png
 
Zuletzt bearbeitet:
tollertyp schrieb:
So viel Text von mir, da muss die Frage untergegangen sein. Ich wiederhole sie gerne:

Also falls du dich über die Zahlen wunderst, einfach mal den Eröffnungspost anschauen. Ich bin so freundlich und mache einen Screenshot:
Anhang anzeigen 1226832
Und nochmals als Erinnerung: Nein, die Punkte sind eigentlich nicht sichtbar für den Nutzer.

Weil nur mal so am Rande: Das ist die Aufgabe. Falls du irgendeine persönliche Programmier-Challenge hast, kein Problem, tobe dich aus: Ich sehe nur keinen Zusammenhang zum Thread.
Das Problem ist doch schon gelöst, kein Grund, mir etwas zu unterstellen. :)
 
pfd schrieb:
Die englischen bezeichnungen für Schranken.
Du hast meinen Beitrag nicht verstanden, und auch nicht, dass die Formeln and und für sich identisch sind - zumindest nehme ich das an, sonst hättest du dir ja nicht die Mühe machen müssen, quasi dasselbe nochmals zu entwickeln.

Und dir nicht mal die Mühe gemacht, dann anzuschauen, was ich verlinkt habe ...
 
Zurück
Oben