0

I would like to implement a function in C# which would take a float number and it would output rounded one as this (always up):

1,527 -> 1,53
1,53 -> 1,6
1,6 -> 2

What's the easiest way to do so?

EDIT: To clear it up a bit - I want this to set proper max value of the 2D graph axis, so if the max value is 1,527, I want to do several iterations of this function until rounded value is higher than e.g. 10%, so for 1,527 the max value could be 1,6 and thus 1,527 fits the graph which is almost fully used at the same time

Calmo
  • 31
  • 5
  • 4
    What's the point? "I will always lose one digit of precision but I'm not doing this to fit the constraints of a display"? Are you sure you've interpreted the requirement correctly? – Damien_The_Unbeliever Aug 09 '18 at 09:30
  • What about truncate it and add 1? `(int)(1,527 + 1)` It's against the rounding principle... – Jeroen van Langen Aug 09 '18 at 09:32
  • 1
    How do you want to treat negative numbers? – Mel Gerats Aug 09 '18 at 09:34
  • 1
    How do you want to treat already round integers? – Rafalon Aug 09 '18 at 09:38
  • `Math.Ceiling` useful if you want to rounding up. However the precision depends on formula you're using, as in [this example](https://stackoverflow.com/questions/7075201/rounding-up-to-2-decimal-places-in-c-sharp). – Tetsuya Yamamoto Aug 09 '18 at 09:42
  • 1
    What do you want to do about the fact that `double d = 1.53;` results in d having the exact value `1.530000000000000026645352591` ? – AakashM Aug 09 '18 at 09:44
  • This seems particularly unuseful for floats. – Magnus Aug 09 '18 at 09:47
  • Negative numbers won't be used. – Calmo Aug 09 '18 at 09:58
  • @AakashM OP never talked about `double`, only `float` – Rafalon Aug 09 '18 at 10:27
  • @Rafalon fine, what does OP want to do about the fact that `float f = 1.53;` results in `f` having the exact value `1.5299999713897705078125` – AakashM Aug 09 '18 at 10:44
  • ^if it won't prevent the number rounding like this `1.5299999713897705078125` -> `1.6` then I don't mind such inaccuracy – Calmo Aug 09 '18 at 10:50
  • @Calmo well but how to know *which* digit is the one to round? You don't have `1.53` but you have `1.529999.....` so following your logic it should become `1.529999971389770507813` and not `1.6` – derpirscher Aug 09 '18 at 11:11
  • I use float so I expect it to be 7 digits accuracy maximum, isn't C# Math.Ceiling handling rounding floats correctly even if they true value is different? I don't need to know or round real values, just the cut-off to float representation ones. Does this what you mention prevent Math.Ceiling working correctly for example with: `Math.Ceiling(1.53*10)/10`? The output here should be `1.6` right? If so, I think I don't need to think about exact values – Calmo Aug 09 '18 at 13:48

4 Answers4

1

Using this question's marked answer:

static void Main()
{
    Console.WriteLine("DECIMAL");

    decimal dTest = 1.527m;
    var dTest2 = dTest;

    while(dTest2 < dTest*1.1m)
    {
        dTest2 = RoundUp(dTest2);
        Console.WriteLine(dTest2);
    }

    Console.WriteLine("FLOAT");

    float fTest = 1.527f;
    var fTest2 = fTest;

    while(fTest2 < fTest*1.1f)
    {
        fTest2 = RoundUp(fTest2);
        Console.WriteLine(fTest2);
    }
}

static decimal RoundUp(decimal input)
{
    int precision = BitConverter.GetBytes(decimal.GetBits(input)[3])[2];

    decimal factor = (decimal)Math.Pow(10,precision-1);

    return Math.Ceiling(input*factor)/factor;
}

static float RoundUp(float input)
{
    return (float)RoundUp((decimal)input);
}

Outputs:

DECIMAL
1.53
1.6
2
FLOAT
1.53
1.6
2

Running example

Rafalon
  • 4,450
  • 2
  • 16
  • 30
0
var a = "1,53";

Split this string into two, and count decimals number:

var length = a.Split(',')[1].Length;

Convert original string to double variable (replacing , to . to avoid Exception during convertation):

var b = Convert.ToDouble(a.Replace(',', '.'))

Perform rounding with the specified precision:

var c = Math.Ceil(b, (length - 1));

And return value with replaced . to ,:

return c.ToString().Replace('.', ',');
Anamnian
  • 417
  • 4
  • 20
0

Why not do it with simple multiplication by powers of 10, this effectively shift the decimal point where you can call Math.Ceiling to round the number up. Divide by the same power of 10 to put the decimal point back where it was.

Using decimal.ToString() to "get around" the problems of floating point precision see this blog post for more information

var values = new[] { 1.527f, 1.53f, 1.6f, -1.527f };

for (var i = 0; i < values.Length; i++)
{
    var val = (decimal)values[i];

    var precision = (decimal.GetBits(val)[3] >> 16 & 0xff) - 1;

    var power = (decimal)Math.Pow(10, precision);

    if (val < 0)
        val = Math.Floor(val * power) / power;
    else
        val = Math.Ceiling(val * power) / power;

    Console.WriteLine(val);
}

Outputs

1.53

1.6

2

-1.53

NOTE Math.Pow and Math.Ceiling are operations on double, hence the cast to double from float

UPDATE Figures out how much decimal places it needs rounding to and uses decimal which "gets around" the issues with floating point precision.

UPDATE 2 Uses decimal.GetBytes to get the number's precision rather than doing the rather cumbersome culture invariant ToString().Split yada yada yada.

UPDATE 3 Rounds away from zero for negative numbers and added bitwise & 0xff to strip off sign bit.

Community
  • 1
  • 1
phuzi
  • 12,078
  • 3
  • 26
  • 50
0

A culture indipendent solution:

static double RoundUp(double val)
{
    double a = val;
    double decimals = a - ((int)a); //Gets only decimals
    double pow = Math.Pow(10, decimals.ToString().Length - 3); 
    a = a * pow;             //Multiply by a power of 10 | decimal shift
    a = Math.Ceiling(a);     //Round up
    a = a / pow;             //Shift back
    return a;
}

and call it like:

var res = RoundUp(1.527); //1.53
res = RoundUp(1.53); //1.6
res = RoundUp(1.6); //2

or for floats:

static float RoundUp(float val)
{
    float a = val;
    float t = a - ((int)a); //Gets only decimals
    float pow = (float)Math.Pow(10, t.ToString().Length - 3); 
    a = a * pow;             //Multiply by a power of 10 | decimal shift
    a = (float)Math.Ceiling(a);     //Round up
    a = a / pow;             //Shift back
    return a;
}


var res = RoundUp(1.527f); //1.53
res = RoundUp(1.53f); //1.6
res = RoundUp(1.6f); //2
Hyarus
  • 922
  • 6
  • 14