[PHP] Complex rounden naar 10-getallen met referentie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik probeer getallen aan de hand van een criteria af te ronden naar een heel getal wat altijd een 10-variant is.

Ik bedoel dus:

19.20 = 19.20 | 19.50 = 20.00 | 19.80 = 20.00 | 20.50 = 20.00 | 20.80 = 20.8

Hierbij wil ik alleen een referentie kunnen stellen waarbij er afgerond mag worden of dat het getal gewoon het getal blijft, bovenstaan is dat .50 bijvoorbeeld.

Ik zou dus het referentiepunt flexibel willen maken, maar dat is voor latere zorg.

Een dergelijke functie als onderstaand zet alles boven de x5 naar x0 omhoog en alles onder de x5 naar x0 naar bendenden

dus:

15= 20
14=10

code:
1
2
3
4
function t_round($num) {
   return ($num % 10 >= 5 ? ceil($num / 10)*10 : floor($num / 10)*10);
   }
print t_round(15);


Ik probeer dus uit te vogelen hoe ik er voor kan zorgen aan de hand van mijn eerste voorbeeld hoe je een referentie punt kun stellen rond een X getal waarbij een veelvoud van de X gewoon X*veelvoud is, echter moet het wel zo zijn dan er altijd afgerond wordt rond de X gebruikmakend van het refrentiegetal dat om X heen mag hangen.

Dit is best lastig om te doen, hoewel het met div/round/mul zou moeten kunnen lukken.

Iemand een helpende hand hierin ?

edit

En stuk code dat het vanaf 19.50 gaat doen naar 20 is:

code:
1
2
3
4
$num2 = 19.1; $rounded2 = round($num2);
if($rounded2 == round($rounded2 / 10) * 10) $num2 = $rounded2;

echo $rounded2;


Alleen bij 20.5 round hij naar 21.

Je zou het ook zo kunnen zien:

20 = 2 met als afwijking 0.50 naar boven en beneden.
30 = 3 met als afwijking 0.50 naar boven en beneden.
etc.

Ik zou alleen graag willen proberen de marge van 0.50 in te stellen in het script, dus hier kies je voor.

Tevens zou je natuurlijk ook kunnen zeggen:

18 = 1 met een afwijking van 2.0
36 = 2 met een afwijking van 2.0

Je kent dus getallen een "waarde" toe met een afwijking in gedachte genomen.

Is dit te realiseren ?

[ Voor 23% gewijzigd door Verwijderd op 02-02-2009 04:04 ]


Acties:
  • 0 Henk 'm!

  • Semyon
  • Registratie: April 2001
  • Laatst online: 15:03
Het is voor jou waarschijnlijk erg duidelijk wat je wilt. Maar ik kan er niet zo veel aanvastknopen.
Wat bedoel je met een 10-variant?
Ik denk dat als je even nadenkt en opschrijft wat je precies wilt dat het probleem opeens ook veel makkelijker is.
dit is natuurlijk heel makkelijk, je deelt door 10 je rondt af en je vermenigvuldigt met 10.

15/10 = 1.5
round(1.5)=2
2*10 = 20

14/10 = 1.4
round(1.5)=1
1*10 = 10
Verwijderd schreef op maandag 02 februari 2009 @ 03:54:

19.20 = 19.20 | 19.50 = 20.00 | 19.80 = 20.00 | 20.50 = 20.00 | 20.80 = 20.8
Het is me helemaal niet duidelijk wat je nu hiermee wilt... Wil je afrond in naar een 0.8 stap?
Dan moet je delen door 0.8, afronden en weer met 0.8 vermenigvuldigen.
Maar waarom je 19.50 dan omhoog wilt hebben? Misschien wil je de ceil hebben?

Probeer eens duidelijk op te schrijven wat je precies wilt

Only when it is dark enough, can you see the stars


Acties:
  • 0 Henk 'm!

  • TheWickedD
  • Registratie: Juli 2002
  • Laatst online: 02-04-2024
Ook ik kan hier niet veel aan vastknopen, maar misschien is de functie die ik eens in MATLAB heb geschreven iets voor jou. Kan hem niet naar php vertalen, maar dat lijkt mij erg simpel.

Matlab:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function out = altround(nr,factor)
% out = altround(nr,factor)
% rounds the elements in NR to the nearest multiple
% of FACTOR.
% 
% FACTOR must be either a scalar or of the same shape as NR.
%
% Thus:
%   altround(12.26,.25) = 12.25;
%   altround(12.2 ,0.6) = 12,
%   but also
%   altround(1449 ,100) = 1400.
%
% DN 2008
% DN 2009-02-02 Support non-scalar factor input

assert(all(isnumeric(factor(:))) && all(isfinite(factor(:))),'Factor argument must be a numeric and finite.')
assert(isscalar(factor) || isequal(size(factor),size(nr)),'Factor argument must be scalar or of the same shape as nr argument.')


factor = 1./factor;

out = round(nr.*factor)./factor;

[ Voor 21% gewijzigd door TheWickedD op 02-02-2009 07:52 . Reden: Toen ik mijn oude code bekeek hem meteen maar even verbeterd ]


Acties:
  • 0 Henk 'm!

Verwijderd

PHP:
1
2
3
if (round($a, 0) % 10 == 0) {
  $a = round($a, 0);
}


dan moet je nog een cornercase afhandelen, maar dat kan je vast prima zelf

8)7 te snel gepost, voortaan hele startpost lezen..

[ Voor 15% gewijzigd door Verwijderd op 02-02-2009 07:56 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Het idee was eerst om alleen 10-tallen (10,20,30,40) af te ronden met een marge van 0.50 naar boven of beneden.

Hierna dacht ik, waarom zie ik niet 10 = 1 en 20 = 2 waarbij ik de marge en het referentiegetal kan aanpassen in mijn code.

Het is een soort punten systeem zou je kunnen zeggen:

10 credits is 1 punt, 20 credits zijn 2 punten. Echter, als je 28 credits hebt betekent dit dat je nog steeds 2 credits hebt. Heb je 29.50 credits dan heb je 3 punten.

Stel ik zou:
[code]

aantal credits = punten

[/credits]

aan willen passen waarbij ik het aantal credits wat 1 punt in houdt bijvorbeel 5 of 7,5 is, dan wil ik ook de marge aan kunnen passen waarbij er afgerond wordt naar een credit. Dus 4,75 zou een punt kunnen zijn waarbij 4,5 het niet meer is in het geval van referentie 5 credits.

Vrij lastige opgaaf vind ik ook welke ik bedacht heb :)

Acties:
  • 0 Henk 'm!

Verwijderd

Wat dacht je van zoiets:

PHP:
1
2
3
4
5
6
7
8
9
<?php
function roundnew($i)
{
   $rest=$i%10;
   $i=$i-$rest;//zie daar je tientallen
   if(9.5<=$rest)
    $i=$i+10;
}
?>

[ Voor 10% gewijzigd door Verwijderd op 02-02-2009 12:44 ]


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Zoals ik het zie heb je dus credits:
PHP:
1
$credits=floor(($punten+0.5)/10)

en dan wil je bij kleine afwijkingen punten terugvervangen of zo?
PHP:
1
if (abs($credits*10-$punten)<=0.5) $punten=$credits*10

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Semyon
  • Registratie: April 2001
  • Laatst online: 15:03
Verwijderd schreef op maandag 02 februari 2009 @ 12:29:
Het idee was eerst om alleen 10-tallen (10,20,30,40) af te ronden met een marge van 0.50 naar boven of beneden.

Hierna dacht ik, waarom zie ik niet 10 = 1 en 20 = 2 waarbij ik de marge en het referentiegetal kan aanpassen in mijn code.

Het is een soort punten systeem zou je kunnen zeggen:

10 credits is 1 punt, 20 credits zijn 2 punten. Echter, als je 28 credits hebt betekent dit dat je nog steeds 2 credits hebt. Heb je 29.50 credits dan heb je 3 punten.
Wat je hier wilt is dus eerst een geheel getal uitrekenen:
X=round(credits)
en vervolgens wil je dat truncen naar een 10tal.
intval(X/10)*10.
[b][message=31442879,noline]
aan willen passen waarbij ik het aantal credits wat 1 punt in houdt bijvorbeel 5 of 7,5 is, dan wil ik ook de marge aan kunnen passen waarbij er afgerond wordt naar een credit. Dus 4,75 zou een punt kunnen zijn waarbij 4,5 het niet meer is in het geval van referentie 5 credits.

Vrij lastige opgaaf vind ik ook welke ik bedacht heb :)
Lijkt me verder simpel eigenlijk :-)
Eerst wil je je rounding aanpassen... Normaal wordt 0.5 omhoog afgerond, nu wil je dat bijvoorbeeld kunnen zetten naar iets willekeurigs.
Omdat 0.25 precies twee keer in 0.5 gaat moet je dus het geheel maal 2 afronden.
X=round(credits*2)/2

Als je vervolgens het truncen niet 10-talig wilt doen, maar met een andere getal, kan je dat vervangen
dus ipv intval(X/10)*10 vervange je de 10 door wat je wilt.

Het lijkt me dus het volgende in pseudo code:


code:
1
2
3
4
roundmargin=0.5/margin
X=round(credits*roundmargin)/roundmargin
X=intval(X/base)*base
return X


Voer je margin=0.5 en base=10 in dan heb je je 10 20 29.5 30 voorbeeld
voer je margin=0.25 en base=5 in dan krijg je voor credits = 4.75 het antwoord 5 en voor credits 4.7 het antwoord 0.

Dat is wat je bedoelt?

Only when it is dark enough, can you see the stars


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dit is exact wat ik bedoel inderdaad. Je uitleg heeft me erg geholpen om ook verder te kijken hoe dergelijke functies werken aangezien ik deze eerder niet nodig gehad heb. Ik dank je dus hartelijk.

Ik ga ook nog even met de rest van de voorbeelden aan de gang om mijn horizon op dat vlak iets meer te verbreden :)

Jullie ook dank !

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Semyon schreef op maandag 02 februari 2009 @ 13:10:
[...]

code:
1
2
3
4
roundmargin=0.5/margin
X=round(credits*roundmargin)/roundmargin
X=intval(X/base)*base
return X


Voer je margin=0.5 en base=10 in dan heb je je 10 20 29.5 30 voorbeeld
voer je margin=0.25 en base=5 in dan krijg je voor credits = 4.75 het antwoord 5 en voor credits 4.7 het antwoord 0.

Dat is wat je bedoelt?
Ik kom er alleen achter dat wanneer ik invul:

$margin = 2;
$base = 15;
$credits = 43;

Dan wordt X toch 30, dit zou dus 45 moeten zijn.

Betekent dit dat ik de 0.5 in het script in dat geval ook aan moet passen ?

Acties:
  • 0 Henk 'm!

Verwijderd

Volgens mij kan het nog simpeler als ik begrijp wat je wilt.

Bijvoorbeeld:

$margin = 2;
$base = 15;
$credits = 43;

$t = $credits + $base; // tel marge bij credits op
$punten = $t % $base; // neem totale aantal keren dat base in t past

Nu is punten in dit geval 3. Eventueel vermenigvuldigen met base om weer op 45 te komen.

voor:

$margin = 0.25;
$base = 5;
$credits = 4.75;

Levert $punten in dit geval 1 op, zoals je wilt. Weet alleen niet of PHP de % operator toestaat op floating points?

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Verwijderd schreef op maandag 02 februari 2009 @ 23:51:
Volgens mij kan het nog simpeler als ik begrijp wat je wilt.

Bijvoorbeeld:

$margin = 2;
$base = 15;
$credits = 43;

$t = $credits + $base; // tel marge bij credits op
$punten = $t % $base; // neem totale aantal keren dat base in t past
Dit zou dus:

$t = $credits + $margin; // tel marge bij credits op
$punten = $t % $base; // neem totale aantal keren dat base in t past

Moeten zijn volgens jou ?

De manier van Semyon werkt erg goed, ik krijg alleen het idee dat er een soort van kantelpunt in zit.

Acties:
  • 0 Henk 'm!

  • b19a
  • Registratie: September 2002
  • Niet online
Verwijderd schreef op maandag 02 februari 2009 @ 23:51:
$t = $credits + $base; // tel marge bij credits op
$punten = $t % $base; // neem totale aantal keren dat base in t past
Bedoel je dan niet dit:
PHP:
1
2
$t = $credits + $margin; // tel marge bij credits op
$punten = floor($t / $base); // neem totale aantal keren dat base in t past

Als je namelijk $t % $base doet dan houd je de rest bij delen over (modulus).

[ Voor 28% gewijzigd door b19a op 03-02-2009 01:38 . Reden: quote ingekort ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
BoukeHaarsma schreef op dinsdag 03 februari 2009 @ 01:38:
[...]


Bedoel je dan niet dit:
PHP:
1
2
$t = $credits + $margin; // tel marge bij credits op
$punten = floor($t / $base); // neem totale aantal keren dat base in t past

Als je namelijk $t % $base doet dan houd je de rest bij delen over (modulus).
Dat doet inderdaad wat ik wil... zover ik snel even test.

Ik ga eens lezen wat de floor() functie doet om me er beter in te kunnen verdiepen.

Dit is echter een manier van bereken die altijd moet kunnen mijn inziens.

Thnx so far.

Acties:
  • 0 Henk 'm!

  • Semyon
  • Registratie: April 2001
  • Laatst online: 15:03
Verwijderd schreef op maandag 02 februari 2009 @ 23:14:
[...]


Ik kom er alleen achter dat wanneer ik invul:

$margin = 2;
$base = 15;
$credits = 43;

Dan wordt X toch 30, dit zou dus 45 moeten zijn.

Betekent dit dat ik de 0.5 in het script in dat geval ook aan moet passen ?
Ah... Dat komt omdat mijn script eerst afrond naar het eerste 2-voud (2 was de margin), dan wordt credits 44 en dan naar de base kijkt...

Ik begrijp nu beter wat je wilt, je wilt het andersom.

Als je bedenkt dat afronden eigenlijk het zelfde is als de marge erbij optellen en de rest weggooien,
dan is het weer simpel

(Om 2.5 normaal af te ronden kan je +0.5 doen en de rest weg gooien)

Wat dacht je van:
code:
1
intval(credits/base+margin/base)*base


voor margin=0.25 base=5.0 levert dat voor credits 4.75->5 op en voor credits 4.7->0 op

even zo met je nieuwe voorbeeld:

margin = 2
base = 15
credits = 43

komt daar 45 uit

Only when it is dark enough, can you see the stars


Acties:
  • 0 Henk 'm!

  • Semyon
  • Registratie: April 2001
  • Laatst online: 15:03
Verwijderd schreef op dinsdag 03 februari 2009 @ 01:45:
[...]


Dat doet inderdaad wat ik wil... zover ik snel even test.

Ik ga eens lezen wat de floor() functie doet om me er beter in te kunnen verdiepen.

Dit is echter een manier van bereken die altijd moet kunnen mijn inziens.

Thnx so far.
Floor gooit de rest weg -> floor (2.5)=2.0
niet zo heel veel anders als een intval, alleen een intval maakt er expliciet een integer van, terwijl floor als resultaat nog een float heeft.

Only when it is dark enough, can you see the stars


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Aha beide manieren doen dus hetzelfde maar werken anders.

Semyon, grappig dat je zegt dat ik het andersom wil... dat gevoel heb ik ook echt als ik je laatste voorbeelden lees... dus je uitleg werkt :)

Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Verwijderd schreef op dinsdag 03 februari 2009 @ 01:55:
Aha beide manieren doen dus hetzelfde maar werken anders.
Nee ze doen dus niet hetzelfde - intval converteert naar een integer en raakt door de limiteringen van het datatype integer de informatie 'achter de komma' kwijt, terwijl floor een floating point value afrond naar het dichtstbijzijnde lagere gehele getal. Dat zijn volstrekt andere dingen met andere outputs.
PHP:
1
2
3
$a = array(floor(2.5), intval(2.5));
foreach($a as $b)
  echo gettype($b)."\n";

Professionele website nodig?


Acties:
  • 0 Henk 'm!

Verwijderd

BoukeHaarsma schreef op dinsdag 03 februari 2009 @ 01:38:
[...]


Bedoel je dan niet dit:
PHP:
1
2
$t = $credits + $margin; // tel marge bij credits op
$punten = floor($t / $base); // neem totale aantal keren dat base in t past

Als je namelijk $t % $base doet dan houd je de rest bij delen over (modulus).
Ja, uiteraard. Niet echt scherp toen ik het typte denk ik.
Pagina: 1