Android Question Round2 limits/errors

Roger Daley

Well-Known Member
Licensed User
Longtime User
Hi all,

A question on the limits of Round2(Number, Decimalplaces). I have found that Round2 returns incorrect results if the combination of Number and Decimalplaces becomes large.
For example:
1. Round2(1.23456789, 18) produces the expected result but Round2(1.23456789, 20) gives 0.09223372
2. Round2(123456.123456, 14) produces 92.23372037E3
The bigger the "Number" the smaller the possible "Decimalplaces"
Obviously the internal process of Round2 is producing "out of range numbers" without a trap/limit/flag.

My question is, does anyone know how to determine the limits the Round2 arguments to an acceptable combination range?

Any help much appreciated

Regards Roger
 

Roger Daley

Well-Known Member
Licensed User
Longtime User
Hi all,

Solution has come to mind, I will post here for others.

Sub MaxRound(Numb)
'Sub to determine the maximum number of decimal places to which "Numb" can be rounded using
'Round2 (Number As Double, DecimalPlaces As Int) As Double

Dim temp1 As Double
Dim MaxRounding As Int
temp1 = Logarithm(Numb,10) 'Take logarithm of number to be rounded
temp1 = Round2(temp1,0) 'Resulting Logarithm rounded to an interger
MaxRounding = 18 - temp1 'Calculate maximum rounding digit as interger
Msgbox(MaxRounding, "Maximum number of digits to which the number can be rounded")
End Sub


Regards Roger
 
Upvote 0

Alberto Michelis

Well-Known Member
Licensed User
Longtime User
Im working with graphs and need to roun the max value for the Y axis.
If I have for example max=280, which function to use to obtain 300?
thanks
 
Upvote 0

Roger Daley

Well-Known Member
Licensed User
Longtime User
Alberto,

I don't quite understand the question or see how rounding is involved.
Can you give a more detailed example. If you need to round a number use Numberformat, otherwise use the Max/Min functions.

Regards Roger
 
Upvote 0

Roger Daley

Well-Known Member
Licensed User
Longtime User
Alberto,

Seeing Erels reply I think I now understand what you are trying to do.

B4X:
Dim roundedValue As Int = 100 * Round(value / 100)
Value=Max=280
roundedValue=300    'Y Axis  fits Max
       or
Value=Max=240
roundedValue=200    'Y Axis  does not fit Max

I suggest you try the Ceil function instead of the Round function. If your max=240 using the Round function would give a Y axis of 200.


Below "N" is determined by the size of Max. IE Max >=10 and Max< 100 "N"=10 Etc.

B4X:
Dim YAxisValue As Int = N * Ceil(value / N)
N=100
Value=Max=280
YAxisValue=300    'Y Axis  fits Max
       or
Value=Max=240
YAxisValue=300    'Y Axis  fits Max

Regards Roger
 
Upvote 0

Mahares

Expert
Licensed User
Longtime User
How about this that will take care of both positive and negative number situations:
B4X:
Log("MyRound:" & RoundValue(161.93)) 'displays 200
Log("MyRound:" & RoundValue(906.8)) 'displays 1000
Log("MyRound:" & RoundValue(-70)) 'displays -100
Log("MyRound:" & RoundValue(280)) 'displays 300
Log("MyRound:" & RoundValue(-280)) 'displays -300
B4X:
Sub RoundValue(x As Double) As Int
   If x > 0 Then
       Return 100 * Ceil(x / 100)
   Else
       Return 100 * Floor(x / 100)
   End If
End Sub
 
Upvote 0

Roycefer

Well-Known Member
Licensed User
Longtime User
And for those who like shoving as much execution as possible into one line at the expense of readability:
B4X:
Sub RoundedValue(x As Double) As Int
     Return (x/Abs(x)) * 100 * Ceil(Abs(x)/100)
End Sub

If your y-axis could be any value within the Int range, you probably don't want to be rounding up to the next hundred. If value=1,854,025, you probably don't want your y-axis to go up to 1,854,100, you probably want it to go up to 2,000,000.
B4X:
Sub RoundedValueGeneral(x As Double) As Int
    Return (x/Abs(x)) * Power(10,Floor(Logarithm(Abs(x),10))) * Ceil(Abs(x)/Power(10,Floor(Logarithm(Abs(x),10))))
End Sub
 
Upvote 0

Roger Daley

Well-Known Member
Licensed User
Longtime User
And for those who like shoving as much execution as possible into one line at the expense of readability:
B4X:
Sub RoundedValue(x As Double) As Int
     Return (x/Abs(x)) * 100 * Ceil(Abs(x)/100)
End Sub

If your y-axis could be any value within the Int range, you probably don't want to be rounding up to the next hundred. If value=1,854,025, you probably don't want your y-axis to go up to 1,854,100, you probably want it to go up to 2,000,000.
B4X:
Sub RoundedValueGeneral(x As Double) As Int
    Return (x/Abs(x)) * Power(10,Floor(Logarithm(Abs(x),10))) * Ceil(Abs(x)/Power(10,Floor(Logarithm(Abs(x),10))))
End Sub


Roycefer,

Re-looked at this again and I have say I am impressed, especially if you wrote that line in one breath. ... and you have simplified a different problem for me. Thanks.

Roger
 
Upvote 0

Roycefer

Well-Known Member
Licensed User
Longtime User
Glad I could help.

The RoundedValueGeneral() sub is an interesting case study in code style choices. While it is certainly the tersest implementation of that logic (it all executes in one line, after all), it is probably not the most efficient implementation. We are forcing the processor to calculate Power(10,Floor(Logarithm(Abs(x),10))) twice, whereas if we did this:
B4X:
Sub RoundedValueGeneral(x As Double) As Int
     Dim powfllog as Double = Power(10,Floor(Logarithm(Abs(x),10)))
     Return (x/Abs(x)) * powfllog * Ceil(Abs(x)/powfllog)
End Sub
the processor only has to calculate it once and retrieve it from L1 cache twice, possibly making it a bit faster. Terse isn't always most efficient. You should add that to your B4Zen wisdom.
 
Upvote 0
Top