Cleanest way to convert a `Double` or `Single` to `Integer`, without rounding
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
supercat
Updated on July 10, 2022Comments
-
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. TheInt
function andMath.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 asInteger
values without a cast.Is there a concise and idiomatic alternative to
IntVar = CInt(Int(FloatingPointVar));
? Pascal includedRound
andTrunc
functions which returnedInteger
; 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
toInt
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 over 11 yearsPlease no. Don’t perform arithmetic operations by converting the number to a string and back. This is inefficient, unnecessary and logically convoluted.
-
supercat over 11 years
Math.Truncate
yields a result of typeDouble
; the above will not compile withoutOption Strict Off
. TheInt
function yields the desired numerical behavior, and would be fine if I wanted to useOption Strict Off
, but that setting makes vb.net a very quirky language. -
Styxxy over 11 yearsYou 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 over 11 yearsI 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 almost 9 yearsHow is this compatible with "Cleanest way to convert..."?
-
Admin about 4 yearsThey do, using the Fix() function. My answer below.
-
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 toInteger
, same as the functions mentioned in the question itself. -
Admin about 4 yearsCasting 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 about 4 years@Undefined That’s nonsense. OP wants the semantics of
CInt(Int(x))
(and not the semantics ofCInt(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 about 4 yearsI'll refer you to the title: "Cleanest way to convert a
Double
orSingle
toInteger
, without rounding" -
Admin about 4 yearsYour 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 about 4 years@Undefined OK, I’ll bite. What way? Why don’t you show it?
-
Admin about 4 yearsDIM 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 about 4 yearsWorst and least efficient way possible.
-
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 aDouble
. (2) OP wants a method using only one function call/cast, not two. OP explicitly does not want to writeCInt(Int(x))
(norCInt(Fix(x))
, which is the same for the purpose of this discussion). -
Admin about 4 yearsI 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 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.