Using C#, I have a few custom classes where I need to be able to detect integer overflows and return a default minimum or maximum value depending on if the overflow was due to the result being over the maximum value or under the minimum value. I can't seem to find a suggestion on how to detect the "type" of overflow that occurs anywhere.
The classes are divided between two general types: ones that use signed values, and ones that use unsigned values.
As an example, here is one of the classes that deals with Int32 values:
public class Stat32Tf : IStat32T<float>
{
#region fields
private int baseValue, baseAdjustment;
private float baseMultiplier;
#endregion
#region ctors
public Stat32Tf()
{
baseValue = 0;
baseAdjustment = 0;
baseMultiplier = 1f;
}
public Stat32Tf(int baseValue, int baseAdjustment = 0, float baseMultiplier = 1f)
{
this.baseValue = baseValue;
this.baseAdjustment = baseAdjustment;
this.baseMultiplier = baseMultiplier;
}
#endregion
#region properties
public int BaseValue
{
get
{
return baseValue;
}
set
{
baseValue = value;
}
}
public int BaseAdjustment
{
get
{
return baseAdjustment;
}
set
{
baseAdjustment = value;
}
}
public float BaseMultiplier
{
get
{
return BaseMultiplier;
}
set
{
baseMultiplier = value;
}
}
public int TruncValue
{
get
{
return (int)Value;
}
}
public float Value
{
get
{
return (baseValue + baseAdjustment) * baseMultiplier;
}
}
#endregion
}
As you can see, the idea of the class is to hold a base value, an adjustment value, and a multiplier value, and return the aggregate value in the Value property. (The TruncValue property just, as it suggests, returns the truncated whole value, dropping any fractional values).
The goal is to handle overflows in the "get" accessor of the Value property and, if the result is over the max int value, return int.MaxValue and if it is under the min value, return int.MinValue, all without throwing the actual overflow error. The part that's making it tricky for me is that the adjustment values and multipliers could be negative values as well (as per the design requirement).
What is a safe way to achieve this? I have not been able to find any resources that address this kind of situation. I'm guessing some sort of arithmetic algorithm will need to be used to determine of results will be over or under.
There are only a limited number of cases where it could underflow:
If baseValue and baseAdjustment are both negative -> If Int.MinValue - baseAdjustment > baseValue then you have an underflow.
If baseValue + baseAjustment is negative and baseMultiplier is positive -> If an overflow exception is raised, then it can only be an underflow.
If baseValue + baseAdjustment is positive but baseMultiplier is negative -> If an overflow exception is raised, then it can only be an underflow.
If you want to avoid raising/catching exception, then it might be a bit more complicated (you may want to cast the result as long and compare it against Int.MaxValue; that way it'll only raise an exception if the result goes over Long.MaxValue).
Floats are pretty big. Are you expecting the get value to overflow or do you expect the cast to int to overflow? If it's just the cast something similar to the following code might work.
//This answer is wrong, see below.
public int TruncValue
{
get
{
if (Value > (float)int.MaxValue)
{
return int.MaxValue
}
else if (Value < (float)int.MinValue)
{
return int.MinValue
}
else
{
return (int)Value;
}
}
}
Although you might need some additional handling for the edge cases.
Edit - I played around with this in some code and found some behavior that I didn't expect, but apparently it is in the specification.
For example,
var Value = int.MaxValue + int.MaxValue //Ends up returning -2 with no exception in debug mode.
var MaxCalculatedValue = (int.MaxValue + int.MaxValue) * float.MaxValue //Ends up returning something like -3.4... ^38.
You really might need to up cast everything into a double and then check to see if the result is greater than or less than an int.
So it might look something like this:
public float Value
{
get
{
var result = ((double)baseValue + (double)baseAdjustment) * (double)baseMultiplier;
if (result > (double)int.MaxValue)
{
return (float)int.MaxValue)
}
if (result < (double)int.MinValue)
{
return (float)int.MinValue)
}
return (float)result;
}
}
Related
When the int variable is more than 10 digits, an error occurs and the number becomes negative.
Why is this happening and how can I solve the problem?
This is my code:
UnityWebRequest www = new UnityWebRequest("https://api.hypixel.net/skyblock/bazaar");
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
JSONNode itemsData = JSON.Parse(www.downloadHandler.text);
unixtimeOnline = itemsData2["lastUpdated"];
Debug.Log(unixtimeOnline);
// output -2147483648
tl;dr
Simply use ulong instead of int for unixtimeOnline
ulong unixtimeOnline = itemsData2["lastUpdated"];
What happened?
As was already mentioned int (or also System.Int32) has 32 bits.
The int.MaxValue is
2147483647
no int can be higher than that. What you get is basically a byte overflow.
From the JSON.Parse I suspect you are using SimpleJson
and if you have
int unixtimeOnline = itemsData2["lastUpdated"];
it will implicitly use
public static implicit operator int(JSONNode d)
{
return (d == null) ? 0 : d.AsInt;
}
which uses AsInt
public virtual int AsInt
{
get { return (int)AsDouble; }
set { AsDouble = value; }
}
which is a problem because a double can hold up to
so when you simply do
double d = 2147483648.0;
int example = (int)d;
you will again get
-2147483648
What you want
You want to use a type that supports larger numbers. Like e.g.
long: goes up to
9,223,372,036,854,775,807
and is actually what system time ticks are usually stored as (see e.g. DateTime.Ticks
or actually since your time is probably never negative anyway directly use the unsigned ones
ulong: goes up to
18,446,744,073,709,551,615
Solution
Long store short: There are implicit conversion for the other numeric values so all you need to do is use
ulong unixtimeOnline = itemsData2["lastUpdated"];
and it will use AsUlong instead
public static implicit operator ulong(JSONNode d)
{
return (d == null) ? 0 : d.AsULong;
}
which now correctly uses
public virtual ulong AsULong
{
get
{
ulong val = 0;
if (ulong.TryParse(Value, out val))
return val;
return 0;
}
set
{
Value = value.ToString();
}
}
As the comment says you will need to use a long variable type
I'm currently trying to implement properties and in particular limiting my setter. For example, i have a 'Money' float field that i'd like it so you can add/subtract values to it but when it's at 0 make it so that it can no longer be subtracted but it can however still be added to.
I see that in the code below that once 'Money' reaches 0 it'll be always stuck at 0. Is there some way to check whether the setter is being added to? I understand that you can check it in the AddMoney or SubtractMoney methods but was more curious if it's possible to do so in the setter.
public float Money {
get {
return this._money;
}
set {
if (_money <= 0){
_money = 0;
} else {
_money = value;
}
}
}
void AddMoney(float addAmount){
Money += addAmount;
}
void SubtractMoney(float subtractAmount){
Money -= subtractAmount;
}
Try to test if the value is negative don't change the Money value :
set {
if (value >= 0)
{
_money = value;
}
else
{
//You may throw exception, or log a warning
}
}
Is it posible to create a method with a decimal argument, that only accepts values from 0 to 1?
Example:
public decimal GetSamplingError(decimal percent){
decimal result = 0;
result = 100*percent;
return result;
}
is it posible to control that the parameter percent is compres between 0 and 1?
Thanks and sorry for my bad english.
no there is no way to control parameter's range, what you can do, is control it inside the function itself, and add a comment to the function
public decimal GetSamplingError(decimal percent){
if(percent > 1)
percent = 1;
else if(percent <0)
percent = 0;
return 100*percent;
}
Or raise an ArgumentOutOfRangeException in case if the parameter is not in dsired range, but it depends on how you would like to manage a worklfow of your application.
I would create my own type of Percent with range checks as others have suggested and some additional stuff. That way, Percent is its own entity in your application and everyone knows when and how to use it. A plain decimal might work as well, I prefer the typed approach however.
internal class Percent
{
private readonly decimal _value;
public decimal Value
{
get { return _value; }
}
public Percent(decimal value)
{
_value = (100 * value);
if (value < 0m || value > 1m)
{
throw new ArgumentOutOfRangeException("value");
}
}
public override string ToString()
{
return String.Format("{0}%", _value);
}
public override int GetHashCode()
{
// HashCode implementation;
}
public override bool Equals(object obj)
{
// Equals implementation;
}
}
There is no way of compile-time checking this. The best solution would be to check the argument at run-time:
public decimal GetSamplingError(decimal percent)
{
if (percent < 0m || percent > 1m)
{
throw new ArgumentException("Percent should be between 0 and 1!", "percent");
}
decimal result = 0;
result = 100*percent;
return result;
}
Other than the approach of Tigran, this will throw an Exception when an invalid argument is passed. I prefer this method over just changing the percent-value, becasue it'll actually make you notice that you passed a wrong value.
When you use Code Contracts of Microsoft, then you could add a contract that ensures that the value is in a specific range. When static checking is enabled, you'll get an error message at compile-time.
Contract.Requires(percent > 0m && percent < 1m, "Percent must be between 0 and 1");
You would have to do:
public decimal GetSamplingError(decimal percent){
if (percent < 0m || percent > 1m)
throw new ArgumentOutOfRangeException("percent", "Must be between 0 and 1.");
// rest of method
}
Of course, it is also possible to make your own struct called DecimalBetweenZeroAndOne which is immutable and holds a decimal field which is readonly and where you write a check to guarantee that the value of the field is always in the required range.
It is possible to validate the input and throw exception if value is not what you expected:
decimal getPercentage(decimal val)
{
if (val < 0 || val > 1)
throw new ArgumentException();
return val * 100;
}
I get the exception "Input string was not in correct format". I want to handle that exception and add my own error. The input should be an int. Where should I do this? I have an objectdatasource with listview and I'm having trouble getting the textbox.text from the code behind so I can use tryParse.
Your property is of type Int32. You cannot assign anything else than a valid integer to this property. Now if you have some user input which is under the form of a string and then you need to assign it to the integer property you could use the int.TryParse method to ensure that the value entered by the user is a valid integer.
For example:
string someValueEnteredByUser = ...
int value;
if (!int.TryParse(someValueEnteredByUser, out value))
{
// the value entered by the user is not a valid integer
}
else
{
// the value is a valid integer => you can use the value variable here
}
Number is always an int, it is defined that way...
You probably want to validate the content of a string. Easiest way is to parse it into an int:
int number;
if(!int.TryParse(yourString, out number))
{
Not an int!
}
'value' will always be of the same type as your variable. Thus having this:
private bool mabool = false;
public bool MaBool
{
get { return mabool; }
set { mabool = value; }
}
Won't ever crash. This because, as I said, value will be the same type of the variable. In this case, value is a boolean.
Try it with a class:
public class Rotator
{
public Roll, Pitch, Yaw;
// Declarations here (...)
}
private Rotator rotation = new Rotator();
public Rotator Rotation
{
get { return rotation; }
set
{
// Since value is of the same type as our variable (Rotator)
// then we can access it's components.
if (value.Yaw > 180) // Limit yaw to a maximum of 180°
value.Yaw = 180;
else if (value.Yaw < -180) // Limit yaw to a minimum of -180°
value.Yaw = -180;
rotation = value;
}
}
As seen on the second example, value is a Rotator, thus we can access it's components.
I recently created a generic Matrix<T> class that acts as a wrapper around a List<List<T>> collection. As far as I can tell, this class is working perfectly. I am running into a slight problem though regarding the default values of the T's.
I create an instance of Matrix<int>(3, 3), which creates a 3x3 matrix of ints, all defaulted to 0 using default(T). I know that value types (which include primitives) default to a 0 equivalent, and reference types default to null. I was wondering if it was possible to change this default value so that if a value type is passed into the Matrix, it would be populated with 5's for example, instead of 0's.
I tried creating my own struct (value type), but due to not being able to use parameterless constructors inside structs, I cannot find a way to change the default value from 0.
I suspect changing the default value is not possible, and I will have to loop through the Matrix cell by cell after it has been instantiated, but I wanted to ask on here just in case before I do that.
public Matrix(int width, int height) : this(width, height, default(T)) {}
public Matrix(int width, int height, T defaultValue)
{
List<T> rows = new List<T>(height);
for (int i = 0; i < height; i++)
{
List<T> columns = new List<T>(width);
for (int j = 0; j < width; j++)
{ columns.Add(defaultValue); }
rows.Add(columns);
}
// store `rows` wherever you are storing it internally.
}
But as Joseph says, there's no way of setting what default(T) evaluates to.
There's no way to change the default value like how you're describing.
var someInt = default(int); //this will always be 0, you can't change it
var someReference = default(SomeClass); //this will always be null
Here's an msdn article on it, although it's not much more descriptive than what's already been said unfortunately.
My understanding of the implementation of default(T) is that the runtime, by default, zeros out the memory as the application requests it, and C# just allocates the space without ever overwriting the zeros. It just so happens that the default values of non-numeric types (e.g. the null reference, false) are represented as zeros in memory. This can lead to some weird behavior; for example, default(MyEnumType) will be zero even if you never specified an enum value to be equal to zero.
You can make a structure that encapsulates it's value and only exposes it with an offset of the default value that you want:
public struct DefaultFiveInteger {
private int _value;
public DefaultFiveInteger(int value) {
_value = x - 5;
}
public static implicit operator int(DefaultFiveInteger x) {
return x._value + 5;
}
public static implicit operator DefaultFiveInteger(int x) {
return new DefaultFiveInteger(x);
}
}
Now you can declare a variable that is initialised to the default value (0), and it will return the value with the offset:
DefaultFiveInteger x;
Console.Write(x);
Output:
5
Well since you're looking at structs already, you could simulate a default value as follows:
public struct MyInt
{
private int _defaultInt;
public int DefaultInt
{
get
{
if (_defaultInt == 0)
return 5;
else
return _defaultInt;
}
set
{
_defaultInt = value;
}
}
}
Combining Guffa's and DougJones ideas you could offset a properties backing member.
public struct MyInt
{
private const int INT_DEFAULT = 5;
private int _defaultInt;
public int DefaultInt
{
get { return _defaultInt + INT_DEFAULT; }
set { _defaultInt = value - INT_DEFAULT; }
}
}