7

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?

Community
  • 1
  • 1
supercat
  • 77,689
  • 9
  • 166
  • 211
  • Not answering your question, just as a point of curiosity: [`Convert.ToInt32`](http://msdn.microsoft.com/en-us/library/303w38b8.aspx) uses yet another rounding method, namely banker’s rounding. – Konrad Rudolph Feb 04 '13 at 17:35
  • @KonradRudolph: Thanks for offering that as a conversion method; it's unfortunately the same method used by `CInt`, though for code written in C# it could be helpful. – supercat Feb 04 '13 at 17:42
  • Ah, I thought (without checking) that `CInt` did round-to-zero, rather than truncation or round-to-even. Anyway, like I said, it’s not an answer. I cannot think of any method of achieving C#’s `(int)` cast in one step in VB (which doesn’t mean that there is no way). – Konrad Rudolph Feb 04 '13 at 18:17
  • @KonradRudolph: Actually, what I'd like would be round-to-negative-infinity. Graphical routines that use round-to-zero often have a visible anomaly at zero, and those that use round-to-even sometimes have anomalies every two pixels (since the sequence (0.5 1.5 2.5 3.5) when rounded becomes (0 2 2 4). Round-to-negative-infinity is clearly useful in many scenarios; I wonder if the various graphics routines use their own internal methods, or what they do? – supercat Feb 04 '13 at 18:46

4 Answers4

4

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.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 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. – supercat Feb 04 '13 at 21:14
  • They do, using the Fix() function. My answer below. –  Jun 10 '20 at 05:03
  • @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. – Konrad Rudolph Jun 10 '20 at 07:25
  • 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. –  Jun 10 '20 at 18:39
  • @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. – Konrad Rudolph Jun 10 '20 at 20:52
  • I'll refer you to the title: "Cleanest way to convert a `Double` or `Single` to `Integer`, without rounding" –  Jun 10 '20 at 22:07
  • 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. –  Jun 11 '20 at 20:27
  • @Undefined OK, I’ll bite. What way? Why don’t you show it? – Konrad Rudolph Jun 11 '20 at 21:15
  • 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. –  Jun 11 '20 at 21:20
  • @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). – Konrad Rudolph Jun 11 '20 at 22:19
  • 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. –  Jun 11 '20 at 23:29
  • @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. – Konrad Rudolph Jun 12 '20 at 08:11
1

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
Styxxy
  • 7,462
  • 3
  • 40
  • 45
  • `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. – supercat Feb 04 '13 at 19:56
  • 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). – Styxxy Feb 04 '13 at 21:01
0

I know this is an old case but I saw no one suggest the Math.Round() function.

Yes Math.Round takes a double and returns a double. However it returns a number that has been rounded to a whole number. It should easily and concisely convert to an integer using cInt. Would that suffice?

cInt(math.round(10000.54564)) ' = 10001 cInt(math.round(10000.49564)) ' = 10000

Ed Ajaz
  • 11
  • 1
-4

You may need extract the Int part of a float number:

float num = 12.234;
string toint = "" + num;
string auxil = toint.Split('.');
int newnum = Int.Parse(auxil[0]);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lindosekai
  • 174
  • 8