Schrift
[thread]9085[/thread]

Runden und kleinste Einheit

Leser: 1


<< |< 1 2 >| >> 14 Einträge, 2 Seiten
esskar
 2007-06-13 16:23
#77498 #77498
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
Moin, moin

hab da mal ein Problem, zu dem ich schon eine unschöne (und wohl umständliche Lösung gefunden hab)
Und zwar hab ich folgendes:

ich habe decimalzahlen in hoher genauigkeit.
diese werden gerundet.
Beispiel:

35,2374528376 => 35,24
542,47123 => 542,47

soweit so gut.
Im obigen Fall ist meine Einheit=0,01 (keine ahnung, ob dass nun wirklich einheit heißen darf, aber ich nenn das mal so)

wäre die einheut 0,001 gewesen, hätte obiges beispiel so ausgesehen

35,2374528376 => 35,237
542,47123 => 542,471

so; leider kann es auch einheiten von 0,5; 0,05; ... geben

das sähe dann so aus
0,5:

35,2374528376 => 35,0
542,47123 => 542,5


0,05:

35,2374528376 => 35,20
542,47123 => 542,45

ich brauche jetzt also eine funktion, die aus einer zahl n und einer einheit u, die auf die einheit gerundete zahl x liefert.

freu mich schon auf die lösungen! ;)

PS: Fragen?
esskar
 2007-06-13 17:29
#77499 #77499
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
hier mal mein c# implementierung
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static decimal ToUnit(decimal number, decimal unit, MidpointRounding mode)
{
if (unit > 1m) unit = 1m;

string unitStr = unit.ToString();
int decimals = 0;

string separator = ThreadHelper.CurrentNumberFormat.NumberDecimalSeparator;
int idx = unitStr.IndexOf(separator);
if (idx >= 0)
{
bool nonZero = false;

unitStr = unitStr.Substring(idx + separator.Length);
foreach (char c in unitStr)
{
if (c == '0' && nonZero) break;
if (c != '0') nonZero = true;
decimals++;
}
}

number = decimal.Round(number, decimals, mode);

decimal i = decimal.ToInt32(number);
decimal f = (decimal)Math.Pow(10d, decimals);
decimal d = (number - i) * f;
decimal u = unit * f;

number = i + (d - d % u) / f;

return number;
}


kommt mir aber nur auf den algorithmus und nicht die sprache an!
PerlProfi
 2007-06-13 20:37
#77500 #77500
User since
2006-11-29
340 Artikel
BenutzerIn
[default_avatar]
Da hast du dir wirklich zu viel Arbeit gemacht, so gehts auch:
n_r = u * sprintf('%.0f', n / u)

Oder als kleine Perlfunktion:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sub tounit($$) {
# pick parameters
my($num, $unit) = @_;

# check parameters
return undef unless looks_like_number($num);
return undef unless looks_like_number($unit);
return $unit unless $unit; # edit

# round number
my $res = $unit * sprintf( '%.0f', $num / $unit );

# return rounded number
return $res;
} # tounit

(check parameters funktioniert nur, wenn looks_like_number() von Scalar::Util mit eingebunden ist)

MfG\n\n

<!--EDIT|PerlProfi|1181827823-->
moritz
 2007-06-13 21:57
#77501 #77501
User since
2007-05-11
923 Artikel
HausmeisterIn
[Homepage]
user image
Ich würde der Rundungs-Funktion von sprintf misstrauen (hab in C damit schlechte Erfahrungen gemacht), und es so machen:

Code (perl): (dl )
1
2
3
4
use POSIX qw(floor);
my $unit = 0.05;
my $number = 12.34567;
my $rounded = $unit * floor(0.5 + $number / $unit);

Das +0.5 garantiert "richtiges" runden, d.h. 0.5 wird zu 1 gerundet, 0.49 zu 0.
Damit geht man auch keinen Weg über einen String.
esskar
 2007-06-13 23:12
#77502 #77502
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
:blush:
danke.
manchmal sieht man den walt wohl vor vielen bäumen nicht!
esskar
 2007-06-14 12:44
#77503 #77503
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
bei einer unit von 0.5 versaut die +0.5 das ergebnis natürlich
esskar
 2007-06-14 12:47
#77504 #77504
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
in c# sieht es jetzt so aus
Code: (dl )
1
2
3
4
5
public static decimal ToUnit(decimal number, decimal unit, MidpointRounding mode)
{
if (unit > 1m) unit = 1m;
return unit * decimal.Round(number / unit, mode);
}
PerlProfi
 2007-06-14 17:29
#77505 #77505
User since
2006-11-29
340 Artikel
BenutzerIn
[default_avatar]
Achja, u == 0 sollte man als Sonderfall behandeln, also einen speziellen Rückgabewert liefern ( evtl. auch 0 ) oder eine exception auslösen, oder ähnliches.
esskar
 2007-06-15 01:41
#77506 #77506
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
in C# wird das einfach zu NaN
esskar
 2007-06-20 10:58
#77507 #77507
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
ich frage mich gerade, inwieweit das hiermit kollidiert
<< |< 1 2 >| >> 14 Einträge, 2 Seiten



View all threads created 2007-06-13 16:23.