(123L).toInt() produces 123 but Long.MAX_VALUE.toInt() produces -1. Clearly this is not correct. Without having to write a lot of boilerplate code, is there a way to get Kotlin to throw an exception when a value is out of range/bounds for the target type?
TL;DR you can make a custom extension function that checks if the value is between Int.MIN_VALUE and Int.MAX_VALUE
fun Long.toIntThrowing() : Int {
if (this < Int.MIN_VALUE || this > Int.MAX_VALUE) {
throw RuntimeException()
}
return this.toInt()
}
The "weird" behavior you are observing is happening, because in Kotlin, Long is represented as a 64 bit signed integer, while Int is represented as a 32 bit signed integer.
While 123L is easily representable by a 32 bit integer, Long.MAX_VALUE will overflow the Integer (almost) twice, resulting in the behavior you are observing.
I believe the example below will illustrate it better:
println((2147483647L).toInt()) // the max 32 bit signed int
println((2147483648L).toInt()) // 1 more overflows it to the min (negative) 32 bit signed int
println((2147483649L).toInt()) // 2 more...
println((Long.MAX_VALUE - 1).toInt())
println((Long.MAX_VALUE).toInt())
results in :
2147483647
-2147483648
-2147483647
-2
-1
From: https://discuss.kotlinlang.org/t/checked-and-unsigned-integer-operations/529/2
Exceptions on arithmetic overflow: this will likely make arithmetics significantly slower, and we don’t see how to avoid it without changes to the JVM, nor are we ready to accept the slowdown
If you are running on the JVM you may use Math.toIntExact:
Returns the value of the long argument; throwing an exception if the value overflows an int.
There doesn't seem to be a pure Kotlin way, but at least you can nicely wrap it:
fun Long.toIntExact() = Math.toIntExact(this)
Related
Consider this silly enum:
enum Number {
Rational {
numerator: i32,
denominator: std::num::NonZeroU32,
},
FixedPoint {
whole: i16,
fractional: u16,
},
}
The data in the Rational variant takes up 8 bytes, and the data in the FixedPoint variant takes up 4 bytes. The Rational variant has a field which must be nonzero, so i would hope that the enum layout rules would use that as a discriminator, with zero indicating the presence of the FixedPoint variant.
However, this:
fn main() {
println!("Number = {}", std::mem::size_of::<Number>(),);
}
Prints:
Number = 12
So, the enum gets space for an explicit discriminator, rather than exploiting the presence of the nonzero field.
Why isn't the compiler able to make this enum smaller?
Although simple cases like Option<&T> can be handled without reserving space for the tag, the layout calculator in rustc is still not clever enough to optimize the size of enums with multiple non-empty variants.
This is issue #46213 on GitHub.
The case you ask about is pretty clear-cut, but there are similar cases where an enum looks like it should be optimized, but in fact can't be because the optimization would preclude taking internal references; for example, see Why does Rust use two bytes to represent this enum when only one is necessary?
what will happen when the integer crosses its limit? The output is 3595 , and how it will come? And it is 2 byte type ?
#include<stdio.h>
#include<conio.h>
void main()
{
int n=12,res=1;
clrscr();
while(n>3)
{
n+=3;
res*=3;
}
printf("%d",n*res);
getch();
}
The program will have undefined behavior.
The condition you gave is non terminating. It's a loop where the condition will never be terminated in a well defined manner.
You will go on multiplying and then once it will overflow. And then if you get a negative result in n or <=3 then it will stop. And in the mean time res has also overflown. As a result you will not be sure how this program behaves. We can't be sure of what the result will be.
The behaviour is undefined - you should not rely on anything specific. Common manifestations on int overflow are:
Wraparound such that 1 + INT_MAX becomes INT_MIN. This is what every Windows PC I have encountered does. The bit pattern produced by the operation matches the unsigned cousin exactly.
Clamping such that 1 + INT_MAX becomes INT_MAX. I last observed this on a machine (with signed magnitude int) running a variant of UNIX in the 1990s.
Kotlin's Long.MIN_VALUE == -9223372036854775808, but when I write:
val minT: Long = -9223372036854775808L //Long.MIN_VALUE
IDEA say it was wrong.
Dmitry Jemerov told me this because the - sign in Kotlin is not part of the constant but rather the unary minus operator applied to the constant value, and 9223372036854775808L is one larger than the maximum possible positive value for the Long type.
But now, why Int is right :
val minI: Int = -2147483648 //Int.MIN_VALUE
Look here:
I believe they bound like that value may need to fall within -9223372036854775808 to 9223372036854775808 because of Long.
I used to think that in 64-bit Obj-C runtime BOOL is actually _Bool and it's a real type so it's safe to write like this:
BOOL a = YES;
BOOL b = NO;
if (a != b) {...}
It's been working seemingly fine but today I found a problem when I use bit field structs like this:
typedef struct
{
BOOL flag1 : 1;
} FlagsType;
FlagsType f;
f.flag1 = YES;
BOOL b = YES;
if (f.flag1 != b)
{
// DOES GET HERE!!!
}
It seems that BOOL returned from the bit field is equal to -1 while the regular BOOL is 1, and they are not equal!!!
Note that I am aware of the situation when an arbitrary integer number is cast to BOOL and therefore becomes a "strange" BOOL which is not safe to compare.
However in this situation, both flag1 field and b were declared as BOOL and never cast. What is the problem? Is this a compiler bug?
The bigger question is if it's really safe to compare BOOLs at all or should I write a XORing helper function? (It would be such a chore, because boolean comparisons are so ubiquitous...)
I do not repeat that using a C boolean type solves the problems one can have with BOOL. That's true – in particular here, as you can read below –, but most of the problems resulted from a wrong storage into a boolean (C) object. But in this case _Bool or unsigned (int) seem to be the only possible solution. (Except of solutions with extra code.) There is a reason for it:
I cannot find a precise documentation of the new behavior of BOOL in Objective-C, but the behavior you found is something between bad and buggy. I expected the latest behavior to be analogous to _Bool. That's not true in your case. (Thanks for finding that out!) Maybe this is for backwards compatibility. To tell the full story:
In C an object of the type int is signed int. (This is a difference to char. For this type the signedess is implementation defined.)
— int, signed, or signed int
ISO/IEC 9899:TC3, 6.7.2-2
Each of the comma-separated sets designates the same type, […]
ISO/IEC 9899:TC3, 6.7.2-5
But there is a weird exception for historical reasons:
If the int object is a bit-field, it is implementation defined, whether it is a signed int or an unsigned int. (Likely this is because some CPUs in the past could not automatically expand the sign of a partial byte integer. So having an unsigned integer is easier, because nulling the top bits is enough.)
On clang the default is signed int. So according to full-width integers int always denotes a signed integer, even it has only one bit. An int member : 1 can only store 0 and -1! (Therefore it is no solution to use int instead.)
Each of the comma-separated sets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier int designates the same type as signed int or the same type as unsigned int.
ISO/IEC 9899:TC3, 6.7.2-5
The C standard says that a boolean bit-field is an integer type and therefore takes part on the weird integer signedness rule for bit-fields:
A bit-field is interpreted as a signed or unsigned integer type consisting of the specified number of bits.
ISO/IEC 9899:TC3, 6.7.2.1-9
This is the behavior you found. Because this is meaningless for 1 bit booleans types, the C standard explicitly denotes that storing a 1 into a boolean bit-field has to compare equal to 1 in every case:
If the value 0 or 1 is stored into a nonzero-width bit-field of type _Bool, the value of the bit-field shall compare equal to the value stored.
ISO/IEC 9899:TC3, 6.7.2.1-9
This leads to the strange situation, that an implementation can implement booleans of width 1 as { 0, -1 }, but has to fulfill 1 == -1. Great.
So, the short story: BOOL behaves like an integer bit-field (conforming to the standard), but does not take part on the extra requirement for _Bools.
I think this is, because of legacy code. (One could expect -1 in the past.)
I'm building a hex calculator in objective-c. My problem is dealing with long long values that would overflow when multiplied.
When I add values before I add i check that the value would not overflow by doing something like this.
long long leftToAdd = LLONG_MAX - self.runningTotal;
if (self.selectedNumber <= leftToAdd) {
self.runningTotal += self.selectedNumber;
} else {
self.selectedNumber -= leftToAdd;
self.runningTotal = self.selectedNumber-1;
self.overflowHasOccured = YES;
}
if the value would overflow it takes the overflow value (without actually overflowing) and adds an overflow notification. I was hoping to find a way to do this same type of thing but for multiplication, can anyone help with this?
here's what i have so far.
// if - value would not overflow //
if (self.runningTotal > 0 && self.selectedNumber > 0
&& LLONG_MAX/self.runningTotal >= self.selectedNumber) {
self.runningTotal *= self.selectedNumber;
// else - handle overflow //
} else {
}
and as a side question would i need to do a similar check for division?
You could check for overflow in multiplication following the same pattern you use for addition - for the later you use subtraction to determine the bound, for the former you would use division:
long long canMultiplyBy = LLONG_MAX / self.runningTotal;
In all cases if you are supporting signed numbers you have to consider underflow as well. Division requires a divide by zero check.
In the C library there are functions for checked arithmetic, lookup check_int64_mul to find the lot (they are all described on the same manual page). These will be efficient and operate directly with primitive value types are you are now doing.
The Clang compiler also provides some checked arithmetic builtin functions, these differ from the C library functions in returning a bool indications and being defined for int, long and long long types rather than int32 and int64. See Checked Arithmetic Builtins.
There are also NSDecimal - a value type, and NSDecimalNumber - an object type built over the former. These provide both extended precision, up to 38 decimal digits, and control over overflow, underflow, divide-by-zero, etc. See NSDecimalNumberBehaviors and NSDecimalNumberHandler.
HTH