Cleanest way to convert a `Double` or `Single` to `Integer`, without rounding

12,470

Solution 1

After some searching, it seems that VB has no clean way of accomplishing that, short of writing an extension method.

The C# (int) cast translates directly into conv.i4 in IL. VB has no such operators, and no framework function seems to provide an alternative.

Usenet had an interesting discussion about this back in 2005 – of course a lot has changed since then but I think this still holds.

Solution 2

You can use the Math.Truncate method.

Calculates the integral part of a specified double-precision floating-point number.

For example:

Dim a As double = 1.6666666
Dim b As Integer = Math.Truncate(a) ' b = 1
Share:
12,470
supercat
Author by

supercat

Updated on July 10, 2022

Comments

  • supercat
    supercat almost 2 years

    Converting a floating-point number to an integer using either CInt or CType will cause the value of that number to be rounded. The Int function and Math.Floor may be used to convert a floating-point number to a whole number, rounding toward negative infinity, but both functions return floating-point values which cannot be implicitly used as Integer values without a cast.

    Is there a concise and idiomatic alternative to IntVar = CInt(Int(FloatingPointVar));? Pascal included Round and Trunc functions which returned Integer; is there some equivalent in either the VB.NET language or in the .NET framework?

    A similar question, CInt does not round Double value consistently - how can I remove the fractional part? was asked in 2011, but it simply asked if there was a way to convert a floating-point number to an integer; the answers suggested a two-step process, but it didn't go into any depth about what does or does not exist in the framework. I would find it hard to believe that the Framework wouldn't have something analogous to the Pascal Trunc function, given that such a thing will frequently be needed when performing graphical operations using floating-point operands [such operations need to be rendered as discrete pixels, and should be rounded in such a way that round(x)-1 = round(x-1) for all x that fit within the range of +/- (2^31-1); even if such operations are rounded, they should use Floor(x+0.5), rather than round-to-nearest-even, so as to ensure the above property]

    Incidentally, in C# a typecast from Double to Int using (type)expr notation uses round-to-zero semantics; the fact that this differs from the VB.NET behavior suggests that one or both languages is using its own conversion routines rather an explicit conversion operator included in the Framework. It would seem likely that the Framework should define a conversion operator? Does such an operator exist within the framework? What does it do? Is there a way to invoke it from C# and/or VB.NET?

  • Konrad Rudolph
    Konrad Rudolph over 11 years
    Please no. Don’t perform arithmetic operations by converting the number to a string and back. This is inefficient, unnecessary and logically convoluted.
  • supercat
    supercat over 11 years
    Math.Truncate yields a result of type Double; the above will not compile without Option Strict Off. The Int function yields the desired numerical behavior, and would be fine if I wanted to use Option Strict Off, but that setting makes vb.net a very quirky language.
  • Styxxy
    Styxxy over 11 years
    You are very right, Option Strict Off is not good. I didn't notice that my VS auto put it like that when creating a console application (otherwise I would've seen a warning).
  • supercat
    supercat over 11 years
    I wonder why Microsoft wouldn't have added some methods to vb or the Framework in all this time [and for that matter, how things like graphics routines handle the issue]? It's not as though non-rounded conversion from floating-point to integer values is exactly an obscure operation.
  • Peter Mortensen
    Peter Mortensen almost 9 years
    How is this compatible with "Cleanest way to convert..."?
  • Admin
    Admin about 4 years
    They do, using the Fix() function. My answer below.
  • Konrad Rudolph
    Konrad Rudolph about 4 years
    @Undefined No. The link in my answer already mentions Fix but also mentions why it doesn’t fulfil OP’s requirement. In a nutshell, Fix returns the wrong type and you still need to cast to Integer, same as the functions mentioned in the question itself.
  • Admin
    Admin about 4 years
    Casting isn't OP's issue, rounding is OP's issue. Fix returns a double, but it is a whole number, without rounding. In essence, an integer.
  • Konrad Rudolph
    Konrad Rudolph about 4 years
    @Undefined That’s nonsense. OP wants the semantics of CInt(Int(x)) (and not the semantics of CInt(Fix(x))!), but more concise. Casting is definitely part of the question. OP said so explicitly in the question, and again in the comment below your answer.
  • Admin
    Admin about 4 years
    I'll refer you to the title: "Cleanest way to convert a Double or Single to Integer, without rounding"
  • Admin
    Admin about 4 years
    Your own words "After some searching, it seems that VB has no clean way of accomplishing that, short of writing an extension method." but you're dead wrong, it does. That's my point.
  • Konrad Rudolph
    Konrad Rudolph about 4 years
    @Undefined OK, I’ll bite. What way? Why don’t you show it?
  • Admin
    Admin about 4 years
    DIM KonradRudolph AS Double = 0.8 KonradRudolph = Cint(Fix(KonradRudolph) Contrary to your statement, I have provided a "clean way of accomplishing it... No extension method written." Casting is extremely standard, a good practice and REQUIRED in Option Strict. You are not allowed to use implicit conversion on differing types. You MUST cast if using Option Strict, which any developer worth his salt would always use.
  • Admin
    Admin about 4 years
    Worst and least efficient way possible.
  • Konrad Rudolph
    Konrad Rudolph about 4 years
    @Undefined I honestly don’t get why this is hard to understand: (1) OP wants the result in an Integer, not a Double. (2) OP wants a method using only one function call/cast, not two. OP explicitly does not want to write CInt(Int(x)) (nor CInt(Fix(x)), which is the same for the purpose of this discussion).
  • Admin
    Admin about 4 years
    I don't know why either but you keep going on about it anyways. You said there IS NO WAY. But there is. I don't care if OP wants to use casting or not, you are REQUIRED to use casting with Option Strict. No choice otherwise. End of story.
  • Konrad Rudolph
    Konrad Rudolph about 4 years
    @Undefined “you are required to use casting” — Yes, and that is exactly what my answer says. In particular, what my answer says is that no VB.NET method or operator directly exposes the conv.i4 IL code, unlike C#, where this operation is exposed by the (int) cast.