Question double , number of decimal places

andrews

Well-known member
Joined
Nov 22, 2011
Messages
169
Programming Experience
5-10
Is there a fast way to get a number of double type with n decimal places.

f.e. x = 0.254789457845128.......
I want x as 0.25478945 with 8 decimals

Thanks for any response
 
I mean 8 decimals places without round, I am using round(x-0.00000005),8) but is it the best and fastest way ?
I there no function in vb.net?
 
Last edited:
There is no single method to do that. Math.Truncate is similar to Math.Round and does what you want but only at the decimal point and not for a specific number of decimal places. Other than what you're doing, the only options I can think of are multiplying the number by the appropriate factor of 10, truncating and then dividing by the same factor of 10 or else converting to a String, using Substring and then converting back to a number. That second option is a real hack but you could write an extension method that used the first option:
Imports System.Runtime.CompilerServices

Friend Module DoubleExtensions

    <Extension>
    Public Function Truncate(source As Double, decimals As Integer) As Double
        Dim wholePart = Math.Truncate(source)
        Dim fractionalPart = source - wholePart

        fractionalPart = fractionalPart * 10 ^ decimals
        fractionalPart = Math.Truncate(fractionalPart)
        fractionalPart = fractionalPart / 10 ^ decimals

        Return wholePart + fractionalPart
    End Function

End Module
Sample usage:
Dim number = 0.254789457845128

MessageBox.Show(number.ToString())

number = number.Truncate(8)

MessageBox.Show(number.ToString())
 
Sorry, little mistake , it should be : I am using round(x-0.000000005,8)
It is the best I see till now, if I am right truncate is only for type decimal
 
Last edited:
Sorry, little mistake , it should be : I am using round(x-0.000000005,8)
It is the best I see till now, if I am right truncate is only for type decimal

You are not right. The Decimal type has its own Truncate method but, as I've shown, the Math.Truncate method works for Double as well as Decimal.
 
Truncate without rounding

Here's a short solution that seems to work:

VB.NET:
    Sub Main()
        Dim mynum As Double = 3.1234567898765
        Dim newnum As Double
        newnum = Math.Round(mynum, 8)  'Round changes the last digit to a 9 instead of 8
        Console.WriteLine("Round to 8:   " & newnum)    'not what you want
        'Truncate to 8 without rounding:
        newnum = Math.Round(mynum, 9)    'or   newnum = mynum
        newnum = newnum - 0.000000005
        newnum = Math.Round(newnum, 8)
        Console.WriteLine("Truncate to 8:   " & newnum)
        Console.ReadLine()
    End Sub

If you don't need the original value of the variable, then you could shorten it to this:

VB.NET:
        Dim mynum As Double = 3.1234567898765
        'Truncate to 8 without rounding:
        mynum = mynum - 0.000000005
        mynum = Math.Round(mynum, 8)
        Console.WriteLine("Truncate to 8:   " & mynum)
 
Last edited:
Yes, but it truncates all the decimals and it is so no solution for my question.
Till now the best I think is round(x-0.000000005,8)
Do I miss something, Jimcilhinney ?
 
Yes, but it truncates all the decimals and it is so no solution for my question.
Till now the best I think is round(x-0.000000005,8)
Do I miss something, Jimcilhinney ?
Um, yes you're missing something. It's like you didn't even bother to read post #5. I already said myself that Math.Truncate will not truncate to a specific number of decimal places so it's no great breakthrough that you worked that out. That would also explain why I wrote a method for you that does what you want and uses Math.Truncate internally. I even provided an example of how to use it. If you're not up to copying a bit of code that I went to the trouble of writing for you then I'm wasting my time here.
 
andrews: I posted before I saw your short solution: round(x-0.000000005,8) is similar to what I had posted above. It works as long as you don't need the original value, or assign it to a different variable.

jmc: Thanks for your input. It wasn't a waste of time. I tried your function and it's worth keeping. (I had written something similar to this using ^ and / for a different purpose a long time ago and I don't remember offhand what it was for.)
 
Last edited:
Yes, Solitaire the same as what I propose.
And I think it is till now the best.

And not the solution Jimcilhinney which is more complicated and not so fast I think.

Imports System.Runtime.CompilerServices

Friend Module DoubleExtensions

<Extension>
Public Function Truncate(source As Double, decimals As Integer) As Double
Dim wholePart = Math.Truncate(source)
Dim fractionalPart = source - wholePart

fractionalPart = fractionalPart * 10 ^ decimals
fractionalPart = Math.Truncate(fractionalPart)
fractionalPart = fractionalPart / 10 ^ decimals

Return wholePart + fractionalPart
End Function

End Module
 
Yes, Solitaire the same as what I propose.
And I think it is till now the best.

And not the solution Jimcilhinney which is more complicated and not so fast I think.

Imports System.Runtime.CompilerServices

Friend Module DoubleExtensions

<Extension>
Public Function Truncate(source As Double, decimals As Integer) As Double
Dim wholePart = Math.Truncate(source)
Dim fractionalPart = source - wholePart

fractionalPart = fractionalPart * 10 ^ decimals
fractionalPart = Math.Truncate(fractionalPart)
fractionalPart = fractionalPart / 10 ^ decimals

Return wholePart + fractionalPart
End Function

End Module

I just used this code to test both options:
Dim source = 0.254789457845128
Dim destination As Double
Dim timer As Stopwatch

timer = Stopwatch.StartNew()

For i = 1 To 100000
    destination = Math.Round(source - 0.000000005, 8)
Next

Dim time1 = timer.Elapsed

timer = Stopwatch.StartNew()

For i = 1 To 100000
    destination = source.Truncate(8)
Next

Dim time2 = timer.Elapsed

MessageBox.Show(String.Format("Round: {1}{0}Truncate: {2}{0}Difference: {3}",
                              Environment.NewLine,
                              time1,
                              time2,
                              time2 - time1))
It showed that using Round was about an order of magnitude faster than using Truncate. The thing is though, Calling Truncate 100,000 times still only takes about 5/100 of a second, so it's not a difference that anyone is ever going to notice unless they're doing some serious number crunching.

The advantage of my approach is that you write the method once and then you can use it as many times as you like in as many places as you like and the code to call it is much neater because all you have to do is specify the number of decimal places you want. Using your approach is less neat and not nearly as clear to anyone who may read it. Making your code as readable as possible is always something to strive for. What do I know though? I've only been doing this for 12 years. I'm sure that you and those few nanoseconds that you save will be very happy together. ;)
 
Your approach is good but :
I can also make a short function with my method and then see about the time it is taken

Public Function TruncateNew(ByVal source As Double, ByVal decimals As Integer) As Double
Dim i As Integer
Dim prod, difference As Double
prod = 10
For i = 1 To decimals
prod = prod * 10
Next
difference = 5 / prod
Return Math.Round(source - difference, decimals)
End Function

a) I found that for i = 1 to decimals .... is a little faster then prod = 10^(decimals+1)
b) defining prod as integer is also a little faster but then decimals <= 8

I calculated 100000000 :
My first method : 2.4 seconds
my function : 11.5 seconds (with prod as integer 10 seconds)
your function : 21.2 seconds

Yes, I do serious number crunching, that is the reason I asked for a fast method but I agree this is very exceptional
So, the programmers can choose.
I thank you for the interest you give to my question




 
Last edited:
Back
Top