Is there a way in C# to use maxvalue when an int would be out of range.
For my purposes I can't use a long.
Example
int a = 842673832;
int b = 2131231321;
int t = a * b;
//if t out of range, t = Int32.MinValue;
You would need to test it before hand or create a very special kind of integer (like CheckedInt in the link).
Option A
To test it before hand, you need a data type which can handle big integer value (say, long):
long t = (long)a * b;
int r = t > int.MaxValue ? int.MaxValue : t < int.MinValue ? : int.MinValue : (int)t;
Option B
To use the special kind of integer, you may need to overload the basic operators too.
In the example in the link, the exception is thrown, but you could change the exception into implementing int.MaxValue or int.MinValue, something like this:
public struct CheckedInt {
private int Value { get; set; }
public CheckedInt(int value)
: this() {
Value = value;
}
public static implicit operator CheckedInt(int me) {
return new CheckedInt(me);
}
public static CheckedInt operator +(CheckedInt lhs, CheckedInt rhs) {
double testResult = (double)lhs.Value + (double)rhs.Value;
if (testResult > int.MaxValue)
return int.MaxValue;
if (testResult < int.MinValue)
return int.MinValue;
return new CheckedInt(lhs.Value + rhs.Value); //note that direct lhs+rhs will cause StackOverflow
}
public static CheckedInt operator -(CheckedInt lhs, CheckedInt rhs) {
double testResult = (double)lhs.Value - (double)rhs.Value;
if (testResult > int.MaxValue)
return int.MaxValue;
if (testResult < int.MinValue)
return int.MinValue;
return new CheckedInt(lhs.Value - rhs.Value); //note that direct lhs-rhs will cause StackOverflow
}
public static CheckedInt operator *(CheckedInt lhs, CheckedInt rhs) {
double testResult = (double)lhs.Value * (double)rhs.Value;
if (testResult > int.MaxValue)
return int.MaxValue;
if (testResult < int.MinValue)
return int.MinValue;
return new CheckedInt(lhs.Value * rhs.Value); //note that direct lhs*rhs will cause StackOverflow
}
public static CheckedInt operator /(CheckedInt lhs, CheckedInt rhs) {
double testResult = (double)lhs.Value / (double)rhs.Value;
if (testResult > int.MaxValue)
return int.MaxValue;
if (testResult < int.MinValue)
return int.MinValue;
return new CheckedInt(lhs.Value / rhs.Value); //note that direct lhs-rhs will cause StackOverflow
}
//Add any other overload that you want
public override string ToString() { //example
return Value.ToString();
}
public bool Equals(CheckedInt otherInt) { //example
return Value == otherInt.Value;
}
}
You can try this by enabling overflow checking
int t;
try
{
int a = 842673832;
int b = 2131231321;
t = checked(a * b);
}
catch (System.OverflowException e)
{
t = Int32.MaxValue;
}
If you want t to be an int and not a larger type like Ian's answer, you can catch at OverflowException and set t to MaxValue. Make sure to wrap the section in a checked keyword to allow overflow checking.
int t = 0;
checked {
try
{
int a = 842673832;
int b = 2131231321;
t = a * b;
}
catch (OverflowException)
{
t = int.MaxValue;
}
}
Related
I was attempting to solve the running median problem (on hackerrank) using a sorted set. Only it's elements don't appear properly sorted.
See it in action here: http://rextester.com/NGBN25779
public class RunningMedian{
List<int> list = new List<int>();
SortedSet<int> sorted = new SortedSet<int>();
public void Add(int num){
list.Add(num);
sorted.Add(num);
}
public double MedianNotWorking(){
return GetMedian(sorted.ToArray());
}
public double MedianWorking(){
int[] arr = list.ToArray();
Array.Sort(arr);
return GetMedian(arr);
}
public double GetMedian(int[] arr){
int idx = list.Count / 2;
if(arr.Length % 2 == 0){
return (double)((double)(arr[idx] + arr[idx-1]) / 2);
}else{
return arr[idx];
}
}
}
static void Main(String[] args) {
int n = Convert.ToInt32(Console.ReadLine());
int[] a = new int[n];
RunningMedian heap = new RunningMedian();
for(int i = 0; i < n; i++){
a[i] = Convert.ToInt32(Console.ReadLine());
heap.Add(a[i]);
//double median = heap.GetMedian();
double median = heap.MedianNotWorking();
Console.WriteLine(median.ToString("F1"));
}
}
For the most part the sorted set does work. However at larger input sizes it begins to give wrong answers. It may not be the optimal solution to the problem but I'm curious as to why it fails at all. C# doesn't have a min-heap / priority queue so why can't sorted sets be used as a substitute?
*Edited to include full code from hackerrank.
Here is an input file.
Input
http://textuploader.com/dovni
Expected
http://textuploader.com/dovnb
Output
http://textuploader.com/dovwj
Conflicts appear near the end
Expected
(Skipping 1-364)
54240.0
54576.5
54913.0
54576.5
54240.0
Results
(Skipping 1-364)
54240.0
54576.5
54913.0
54963.0
54576.5
SortedSet collections contain by definition only unique values. However your input file contains the number 21794 twice, which means that the second 21794 entry doesn't get added to your SortedSet. So your sorted set will contain fewer values than your list and your whole algorithm doesn't work anymore.
In general, this could be achieved by definition of new IComparator behavior for the SortedSet comparison. For the min priority queue it would be smth like this:
public class PriorityQueue<K,V> where K : IComparable
where V : IComparable
{
private SortedSet<Node<K,V>> _set;
private readonly int _amount;
public PriorityQueue(int amount)
{
_set = new SortedSet<Node<K,V>>(new PriorityComparer<K,V>());
_amount = amount;
}
public void Add(Node<K,V> value)
{
if (_amount > _set.Count)
_set.Add(value);
else
{
if (_set.Max.Val.CompareTo(value.Val) == 1)
{
_set.Remove(_set.Max);
_set.Add(value);
}
}
}
public Node<K,V> ExtractMax()
{
var max = _set.Max;
_set.Remove(max);
return max;
}
public Node<K,V> ExtractMin()
{
var min = _set.Min;
_set.Remove(min);
return min;
}
public bool IsEmpty => _set.Count == 0;
}
public struct Node<K,V> where K : IComparable
where V : IComparable
{
public K Key;
public V Val;
public Node(K key, V val)
{
Val = val;
Key = key;
}
}
public class PriorityComparer<K,V> : IComparer<Node<K,V>> where K: IComparable
where V: IComparable
{
public int Compare(Node<K,V> i, Node<K,V> y)
{
var compareresult = i.Val.CompareTo(y.Val);
if (compareresult == 0)
return i.Key.CompareTo(y.Key);
return compareresult;
}
}
How would i create a type that works with integers, supports at least addition substraction division and multiplication and guarantees and integer number IF the operation leads to an integer (otherwise throw).
For example i'd like to be able to do something like:
Precise A = 10;
A.Divide(3);
A.GetNumber(); // This would throw an exception as 10/3 isn't an int.
A.Multiply(6);
int result = A.GetNumber; // I want result to be = to 20, not to a floating point type that would round to 2 or be very close like 1.9999999999999999999999998992
I realise this is a odd use case but i do have this need (performing a sequence of operations, which in floating point could be missrepresented, but are guaranteed to end up as a valid int).
Because we can't know that 10 / 3 will eventually result in a precise integer answer until after the * 6 we have to defer it until then with a promise:
public sealed class Precise
{
private interface IOperation
{
int Calculate(int value);
IOperation Combine(IOperation next);
}
private sealed class NoOp : IOperation
{
public static NoOp Instance = new NoOp();
public int Calculate(int value)
{
return value;
}
public IOperation Combine(IOperation next)
{
return next;
}
}
private sealed class Combo : IOperation
{
private readonly IOperation _first;
private readonly IOperation _second;
public Combo(IOperation first, IOperation second)
{
_first = first;
_second = second;
}
public int Calculate(int value)
{
return _second.Calculate(_first.Calculate(value));
}
public IOperation Combine(IOperation next)
{
return new Combo(_first, _second.Combine(next));
}
}
private sealed class Mult : IOperation
{
private readonly int _multiplicand;
public Mult(int multiplicand)
{
_multiplicand = multiplicand;
}
public int Calculate(int value)
{
return value * _multiplicand;
}
public int Multiplicand
{
get { return _multiplicand; }
}
public IOperation Combine(IOperation next)
{
var nextMult = next as Mult;
if(nextMult != null)
return new Mult(_multiplicand * nextMult._multiplicand);
var nextDiv = next as Div;
if(nextDiv != null)
{
int divisor = nextDiv.Divisor;
if(divisor == _multiplicand)
return NoOp.Instance;//multiplcation by 1
if(divisor > _multiplicand)
{
if(divisor % _multiplicand == 0)
return new Div(divisor / _multiplicand);
}
if(_multiplicand % divisor == 0)
return new Mult(_multiplicand / divisor);
}
return new Combo(this, next);
}
}
private sealed class Div : IOperation
{
private readonly int _divisor;
public Div(int divisor)
{
_divisor = divisor;
}
public int Divisor
{
get { return _divisor; }
}
public int Calculate(int value)
{
int ret = value / _divisor;
if(value != ret * _divisor)
throw new InvalidOperationException("Imprecise division");
return ret;
}
public IOperation Combine(IOperation next)
{
var nextDiv = next as Div;
if(nextDiv != null)
return new Div(_divisor * nextDiv._divisor);
var nextMult = next as Mult;
if(nextMult != null)
{
var multiplicand = nextMult.Multiplicand;
if(multiplicand == _divisor)
return NoOp.Instance;
if(multiplicand > _divisor)
{
if(multiplicand % _divisor == 0)
return new Mult(multiplicand / _divisor);
}
else if(_divisor % multiplicand == 0)
return new Div(multiplicand / _divisor);
}
return new Combo(this, next);
}
}
private sealed class Plus : IOperation
{
private readonly int _addend;
public Plus(int addend)
{
_addend = addend;
}
public int Calculate(int value)
{
return value + _addend;
}
public IOperation Combine(IOperation next)
{
var nextPlus = next as Plus;
if(nextPlus != null)
{
int newAdd = _addend + nextPlus._addend;
return newAdd == 0 ? (IOperation)NoOp.Instance : new Plus(newAdd);
}
return new Combo(this, next);
}
}
private readonly int _value;
private readonly IOperation _operation;
public static readonly Precise Zero = new Precise(0);
private Precise(int value, IOperation operation)
{
_value = value;
_operation = operation;
}
public Precise(int value)
: this(value, NoOp.Instance)
{
}
public int GetNumber()
{
return _operation.Calculate(_value);
}
public static explicit operator int(Precise value)
{
return value.GetNumber();
}
public static implicit operator Precise(int value)
{
return new Precise(value);
}
public override string ToString()
{
return GetNumber().ToString();
}
public Precise Multiply(int multiplicand)
{
if(multiplicand == 0)
return Zero;
return new Precise(_value, _operation.Combine(new Mult(multiplicand)));
}
public static Precise operator * (Precise precise, int value)
{
return precise.Multiply(value);
}
public Precise Divide(int divisor)
{
return new Precise(_value, _operation.Combine(new Div(divisor)));
}
public static Precise operator / (Precise precise, int value)
{
return precise.Divide(value);
}
public Precise Add(int addend)
{
return new Precise(_value, _operation.Combine(new Plus(addend)));
}
public Precise Subtract(int minuend)
{
return Add(-minuend);
}
public static Precise operator + (Precise precise, int value)
{
return precise.Add(value);
}
public static Precise operator - (Precise precise, int value)
{
return precise.Subtract(value);
}
}
Here each Precise has both an integer value and an operation that will be performed on it. Further operations produce a new Precise (doing this sort of thing as a mutable is crazy) with a new operation but when possible those operations are combined into a single simpler operation. Hence "divide by three then multiply by six" becomes "multiply by two".
We can test this thus:
public static void Main(string[] args)
{
Precise A = 10;
A /= 3;
try
{
var test = (int)A;
}
catch(InvalidOperationException)
{
Console.Error.WriteLine("Invalid operation attempted");
}
A *= 6;
int result = (int)A;
Console.WriteLine(result);
// Let's do 10 / 5 * 2 = 4 because it works but can't be pre-combined:
Console.WriteLine(new Precise(10) / 5 * 2);
// Let's do 10 / 5 * 2 - 6 + 4 == 2 to mix in addition and subtraction:
Console.WriteLine(new Precise(10) / 5 * 2 - 6 + 4);
Console.Read();
}
A good solution would also deal well with operations done where the LHS was an integer and the RHS a Precise and where both where a Precise; left as an exercise for the reader ;)
Sadly we have to get much more complicated to handle (10 / 3 + 1) * 3, with the improvement having to be made in the Combine implementations.
Edit: Musing a bit further on the issues of doing the above well enough to catch at least most of the edge cases, I think it should start with only dealing with operations between two Precise objects, because going int -> Precise is trivial and can easily be put on top, but going Precise -> int requires a call to the calculation, perhaps too early. I'd also make the operations the key thing acted upon (have the operation store one or two objects which in turn contain an operation or a value). Then if you started with a representation of the sum (10 / 3) + 5 and multiplied it by 6 it's easier to turn that into (10 * (6 / 3)) + (5 * 6) which upon final calculation can give the precise result 50 rather than fail because it hits the imprecise 10 / 3.
If you don't allow arbitrary precision rationals, it seems that you are asking the impossible without more constraints.
Take 1 and divide it by 65537 twice, then multiply by 65537 twice to retrieve 1: this can't fit in 32 bits integers.
Then round final answer using Math.Round().
I would use a decimal for the result of operation and on the GetNumber check on the .ToString if there is a "." If yes I throw an Exception, if not I convert it to an int.
I have a huge array that contains reference type elements, and I want to create a lot of other arrays that essentially just point to specific parts of that one big array.
In other words, I want to create "indexers" or "pointers with lengths".
In C++ it's easy to do so using pointers and for each pointer assign a length, for example create a struct which contains a pointer with a length.
How can I achieve this in C#/.NET?
The whole point is to avoid copying anything, I just want pointers to specific parts in an array that already exists in memory.
Any ideas?
Jon's suggestion of using ArraySegment<T> is likely what you want. If however you are wanting to represent a pointer to the interior of an array, the way you can in C++, here's some code for that. No warranty is expressed or implied, use at your own risk.
This code does not track the "length" of the interior pointer in any way, but it is quite easy to add that feature if you want.
internal struct ArrayPtr<T>
{
public static ArrayPtr<T> Null { get { return default(ArrayPtr<T>); } }
private readonly T[] source;
private readonly int index;
private ArrayPtr(ArrayPtr<T> old, int delta)
{
this.source = old.source;
this.index = old.index + delta;
Debug.Assert(index >= 0);
Debug.Assert(index == 0 || this.source != null && index < this.source.Length);
}
public ArrayPtr(T[] source)
{
this.source = source;
index = 0;
}
public bool IsNull()
{
return this.source == null;
}
public static bool operator <(ArrayPtr<T> a, ArrayPtr<T> b)
{
Debug.Assert(Object.ReferenceEquals(a.source, b.source));
return a.index < b.index;
}
public static bool operator >(ArrayPtr<T> a, ArrayPtr<T> b)
{
Debug.Assert(Object.ReferenceEquals(a.source, b.source));
return a.index > b.index;
}
public static bool operator <=(ArrayPtr<T> a, ArrayPtr<T> b)
{
Debug.Assert(Object.ReferenceEquals(a.source, b.source));
return a.index <= b.index;
}
public static bool operator >=(ArrayPtr<T> a, ArrayPtr<T> b)
{
Debug.Assert(Object.ReferenceEquals(a.source, b.source));
return a.index >= b.index;
}
public static int operator -(ArrayPtr<T> a, ArrayPtr<T> b)
{
Debug.Assert(Object.ReferenceEquals(a.source, b.source));
return a.index - b.index;
}
public static ArrayPtr<T> operator +(ArrayPtr<T> a, int count)
{
return new ArrayPtr<T>(a, +count);
}
public static ArrayPtr<T> operator -(ArrayPtr<T> a, int count)
{
return new ArrayPtr<T>(a, -count);
}
public static ArrayPtr<T> operator ++(ArrayPtr<T> a)
{
return a + 1;
}
public static ArrayPtr<T> operator --(ArrayPtr<T> a)
{
return a - 1;
}
public static implicit operator ArrayPtr<T>(T[] x)
{
return new ArrayPtr<T>(x);
}
public static bool operator ==(ArrayPtr<T> x, ArrayPtr<T> y)
{
return x.source == y.source && x.index == y.index;
}
public static bool operator !=(ArrayPtr<T> x, ArrayPtr<T> y)
{
return !(x == y);
}
public override bool Equals(object x)
{
if (x == null) return this.source == null;
var ptr = x as ArrayPtr<T>?;
if (!ptr.HasValue) return false;
return this == ptr.Value;
}
public override int GetHashCode()
{
unchecked
{
int hash = this.source == null ? 0 : this.source.GetHashCode();
return hash + this.index;
}
}
public T this[int index]
{
get { return source[index + this.index]; }
set { source[index + this.index] = value; }
}
}
Now we can do stuff like:
double[] arr = new double[10];
var p0 = (ArrayPtr<double>)arr;
var p5 = p0 + 5;
p5[0] = 123.4; // sets arr[5] to 123.4
var p7 = p0 + 7;
int diff = p7 - p5; // 2
It sounds like you're looking for something like ArraySegment<T>. Contrary to my earlier thoughts, it does have an indexer and implement IEnumerable<T> etc - it's just done with explicit interfaces.
Sample code:
using System;
using System.Collections.Generic;
static class Test
{
static void Main()
{
string[] original = { "The", "quick", "brown", "fox", "jumped", "over",
"the", "lazy", "dog" };
IList<string> segment = new ArraySegment<string>(original, 3, 4);
Console.WriteLine(segment[2]); // over
foreach (var word in segment)
{
Console.WriteLine(word); // fox jumped over the
}
}
}
EDIT: As noted in comments, ArraySegment<T> is only really "fully functional" in .NET 4.5. The .NET 4 version doesn't implement any interfaces.
You could use LINQ:
yourArray.Skip(startIndex).Take(numberToTake)
The query is lazily evaluated.
I want to have a number (let's say i) whose range is between 0 to 26 so that when the number is 26 and it is incremented by 1 (say i++) the value returns to 0 (i.e. the value is circular).
Is there such a thing in c#? What is it called? If not then how would I implement this in code (overloaded operators are accepted).
Make a property that limits the value:
private int _value;
public int Value {
get { return _value; }
set { _value = value % 27; }
}
Now when you increase the property the setter will limit the value.
Example:
Value = 25;
Value++; // Value is now 26
Value++; // Value is now 0
Value++; // Value is now 1
You can try this:
int result = number % 27;
Use modulus operator (%)
var x = 0;
x = (x+1) % 27;
if you want it to go 0,1,2,3, ..... 24,25,26, 0, 1, 2, 3, ...
use modulus 27
I don't know of any sort of 'boundaries' or rules, you can "set" for an int in the way you want. I'd suggest creating an if statement, or two, to control it. `
if( i <= 26 & i >= 0)
{ ..do something..}
else i = 0;
Something like this should accomplish what you ask:
class CircularInt
{
public int value;
public static CircularInt operator ++(CircularInt c)
{
if (c.value >= 26)
c.value = 0;
else
c.value++;
return c;
}
}
Then use it:
CircularInt cInt = new CircularInt();
cInt++;
Console.WriteLine(cInt.value);
Another option is to define your own immutable type.
public struct Value27
{
private readonly int val;
private readonly bool isDef;
private Value27(int value)
{
while (value < 0) value += 27;
val = value % 27;
isDef = true;
}
public static Value27 Make(int value)
{ return new Value27(value); }
public bool HasValue { get { return isDef; } }
public int Value { get { return val; } }
public static Value27 operator +(Value27 curValue)
{ return Make(curValue.Value + 1); }
public static Value27 operator -(Value27 curValue)
{ return Make(curValue.Value + 26); }
public static implicit operator Value27(int bValue)
{ return Make(bValue); }
public static implicit operator int (Value27 value)
{ return value.Value; }
}
tl;dr: What's wrong with my Cur (currency) structure?
tl;dr 2: Read the rest of the question please, before giving an example with float or double. :-)
I'm aware that this question has come up numerous times before all around the internet, but I have not yet seen a convincing answer, so I thought I'd ask again.
I fail to understand why using a non-decimal data type is bad for handling money. (That refers to data types that store binary digits instead of decimal digits.)
True, it's not wise to compare two doubles with a == b. But you can easily say a - b <= EPSILON or something like that.
What is wrong with this approach?
For instance, I just made a struct in C# that I believe handles money correctly, without using any decimal-based data formats:
struct Cur
{
private const double EPS = 0.00005;
private double val;
Cur(double val) { this.val = Math.Round(val, 4); }
static Cur operator +(Cur a, Cur b) { return new Cur(a.val + b.val); }
static Cur operator -(Cur a, Cur b) { return new Cur(a.val - b.val); }
static Cur operator *(Cur a, double factor) { return new Cur(a.val * factor); }
static Cur operator *(double factor, Cur a) { return new Cur(a.val * factor); }
static Cur operator /(Cur a, double factor) { return new Cur(a.val / factor); }
static explicit operator double(Cur c) { return Math.Round(c.val, 4); }
static implicit operator Cur(double d) { return new Cur(d); }
static bool operator <(Cur a, Cur b) { return (a.val - b.val) < -EPS; }
static bool operator >(Cur a, Cur b) { return (a.val - b.val) > +EPS; }
static bool operator <=(Cur a, Cur b) { return (a.val - b.val) <= +EPS; }
static bool operator >=(Cur a, Cur b) { return (a.val - b.val) >= -EPS; }
static bool operator !=(Cur a, Cur b) { return Math.Abs(a.val - b.val) < EPS; }
static bool operator ==(Cur a, Cur b) { return Math.Abs(a.val - b.val) > EPS; }
bool Equals(Cur other) { return this == other; }
override int GetHashCode() { return ((double)this).GetHashCode(); }
override bool Equals(object o) { return o is Cur && this.Equals((Cur)o); }
override string ToString() { return this.val.ToString("C4"); }
}
(Sorry for changing the name Currency to Cur, for the poor variable names, for omitting the public, and for the bad layout; I tried to fit it all onto the screen so that you could read it without scrolling.) :)
You can use it like:
Currency a = 2.50;
Console.WriteLine(a * 2);
Of course, C# has the decimal data type, but that's beside the point here -- the question is about why the above is dangerous, not why we shouldn't use decimal.
So would someone mind providing me with a real-world counterexample of a dangerous statement that would fail for this in C#? I can't think of any.
Thanks!
Note: I am not debating whether decimal is a good choice. I'm asking why a binary-based system is said to be inappropriate.
Floats aren't stable for accumulating and decrementing funds. Here's your actual example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BadFloat
{
class Program
{
static void Main(string[] args)
{
Currency yourMoneyAccumulator = 0.0d;
int count = 200000;
double increment = 20000.01d; //1 cent
for (int i = 0; i < count; i++)
yourMoneyAccumulator += increment;
Console.WriteLine(yourMoneyAccumulator + " accumulated vs. " + increment * count + " expected");
}
}
struct Currency
{
private const double EPSILON = 0.00005;
public Currency(double value) { this.value = value; }
private double value;
public static Currency operator +(Currency a, Currency b) { return new Currency(a.value + b.value); }
public static Currency operator -(Currency a, Currency b) { return new Currency(a.value - b.value); }
public static Currency operator *(Currency a, double factor) { return new Currency(a.value * factor); }
public static Currency operator *(double factor, Currency a) { return new Currency(a.value * factor); }
public static Currency operator /(Currency a, double factor) { return new Currency(a.value / factor); }
public static Currency operator /(double factor, Currency a) { return new Currency(a.value / factor); }
public static explicit operator double(Currency c) { return System.Math.Round(c.value, 4); }
public static implicit operator Currency(double d) { return new Currency(d); }
public static bool operator <(Currency a, Currency b) { return (a.value - b.value) < -EPSILON; }
public static bool operator >(Currency a, Currency b) { return (a.value - b.value) > +EPSILON; }
public static bool operator <=(Currency a, Currency b) { return (a.value - b.value) <= +EPSILON; }
public static bool operator >=(Currency a, Currency b) { return (a.value - b.value) >= -EPSILON; }
public static bool operator !=(Currency a, Currency b) { return Math.Abs(a.value - b.value) <= EPSILON; }
public static bool operator ==(Currency a, Currency b) { return Math.Abs(a.value - b.value) > EPSILON; }
public bool Equals(Currency other) { return this == other; }
public override int GetHashCode() { return ((double)this).GetHashCode(); }
public override bool Equals(object other) { return other is Currency && this.Equals((Currency)other); }
public override string ToString() { return this.value.ToString("C4"); }
}
}
On my box this gives $4,000,002,000.0203 accumulated vs. 4000002000 expected in C#. It's a bad deal if this gets lost over many transactions in a bank - it doesn't have to be large ones, just many. Does that help?
Usually monetary calculations require exact results, not just accurate results. float and double types cannot accurately represent the whole range of base 10 real numbers. For instance, 0.1 cannot be represented by a floating-point variable. What will be stored is the nearest representable value, which may be a number such as 0.0999999999999999996. Try it out for yourself by unit testing your struct - for example, attempt 2.00 - 1.10.
I'm not sure why you're shrugging off J Trana's answer as irrelevant. Why don't you try it yourself? The same example works with your struct too. You just need to add a couple extra iterations because you're using a double instead of a float, which gives you a bit more precision. Just delays the problem, doesn't get rid of it.
Proof:
class Program
{
static void Main(string[] args)
{
Currency currencyAccumulator = new Currency(0.00);
double doubleAccumulator = 0.00f;
float floatAccumulator = 0.01f;
Currency currencyIncrement = new Currency(0.01);
double doubleIncrement = 0.01;
float floatIncrement = 0.01f;
for(int i=0; i<100000000; ++i)
{
currencyAccumulator += currencyIncrement;
doubleAccumulator += doubleIncrement;
floatAccumulator += floatIncrement;
}
Console.WriteLine("Currency: {0}", currencyAccumulator);
Console.WriteLine("Double: {0}", doubleAccumulator);
Console.WriteLine("Float: {0}", floatAccumulator);
Console.ReadLine();
}
}
struct Currency
{
private const double EPSILON = 0.00005;
public Currency(double value) { this.value = value; }
private double value;
public static Currency operator +(Currency a, Currency b) { return new Currency(a.value + b.value); }
public static Currency operator -(Currency a, Currency b) { return new Currency(a.value - b.value); }
public static Currency operator *(Currency a, double factor) { return new Currency(a.value * factor); }
public static Currency operator *(double factor, Currency a) { return new Currency(a.value * factor); }
public static Currency operator /(Currency a, double factor) { return new Currency(a.value / factor); }
public static Currency operator /(double factor, Currency a) { return new Currency(a.value / factor); }
public static explicit operator double(Currency c) { return System.Math.Round(c.value, 4); }
public static implicit operator Currency(double d) { return new Currency(d); }
public static bool operator <(Currency a, Currency b) { return (a.value - b.value) < -EPSILON; }
public static bool operator >(Currency a, Currency b) { return (a.value - b.value) > +EPSILON; }
public static bool operator <=(Currency a, Currency b) { return (a.value - b.value) <= +EPSILON; }
public static bool operator >=(Currency a, Currency b) { return (a.value - b.value) >= -EPSILON; }
public static bool operator !=(Currency a, Currency b) { return Math.Abs(a.value - b.value) <= EPSILON; }
public static bool operator ==(Currency a, Currency b) { return Math.Abs(a.value - b.value) > EPSILON; }
public bool Equals(Currency other) { return this == other; }
public override int GetHashCode() { return ((double)this).GetHashCode(); }
public override bool Equals(object other) { return other is Currency && this.Equals((Currency)other); }
public override string ToString() { return this.value.ToString("C4"); }
}
Result:
Currency: $1,000,000.0008
Double: 1000000.00077928
Float: 262144
We're only up to .08 cents, but eventually that'll add up.
Your edit:
static void Main(string[] args)
{
Currency c = 1.00;
c /= 100000;
c *= 100000;
Console.WriteLine(c);
Console.ReadLine();
}
}
struct Currency
{
private const double EPS = 0.00005;
private double val;
public Currency(double val) { this.val = Math.Round(val, 4); }
public static Currency operator +(Currency a, Currency b) { return new Currency(a.val + b.val); }
public static Currency operator -(Currency a, Currency b) { return new Currency(a.val - b.val); }
public static Currency operator *(Currency a, double factor) { return new Currency(a.val * factor); }
public static Currency operator *(double factor, Currency a) { return new Currency(a.val * factor); }
public static Currency operator /(Currency a, double factor) { return new Currency(a.val / factor); }
public static Currency operator /(double factor, Currency a) { return new Currency(a.val / factor); }
public static explicit operator double(Currency c) { return Math.Round(c.val, 4); }
public static implicit operator Currency(double d) { return new Currency(d); }
public static bool operator <(Currency a, Currency b) { return (a.val - b.val) < -EPS; }
public static bool operator >(Currency a, Currency b) { return (a.val - b.val) > +EPS; }
public static bool operator <=(Currency a, Currency b) { return (a.val - b.val) <= +EPS; }
public static bool operator >=(Currency a, Currency b) { return (a.val - b.val) >= -EPS; }
public static bool operator !=(Currency a, Currency b) { return Math.Abs(a.val - b.val) < EPS; }
public static bool operator ==(Currency a, Currency b) { return Math.Abs(a.val - b.val) > EPS; }
public bool Equals(Currency other) { return this == other; }
public override int GetHashCode() { return ((double)this).GetHashCode(); }
public override bool Equals(object o) { return o is Currency && this.Equals((Currency)o); }
public override string ToString() { return this.val.ToString("C4"); }
}
Prints $0.
Mehrdad, I don't think I could convince you if I brought in the entire SEC. Now, your entire class basically implements BigInteger arithmetic with an implied shift of 2 decimal places. (It should be at least 4 for accounting purposes, but we can change 2 to 4 easily enough.)
What advantage do we have backing this class with double instead of BigDecimal (or longlong if something like that is available)? For the advantage of a primitive type I pay with expensive rounding operations. And I also pay with inaccuracies. [Example from here 1]
import java.text.*;
public class CantAdd {
public static void main(String[] args) {
float a = 8250325.12f;
float b = 4321456.31f;
float c = a + b;
System.out.println(NumberFormat.getCurrencyInstance().format(c));
}
}
OK, here we backed with a float instead of a double, but shouldn't that be a BIG warning flag that the whole concept is wrong and that we may get in trouble if we have to make millions of calculations?
Every professional who works in finance believes that floating-point representation of money are a bad idea. (See, among dozens of hits, http://discuss.joelonsoftware.com/default.asp?design.4.346343.29.) Which is more likely: they are all stupid, or floating-point money is indeed a bad idea?
Cur c = 0.00015;
System.Console.WriteLine(c);
// rounds to 0.0001 instead of the expected 0.0002
The problem is that 0.00015 in binary is really 0.00014999999999999998685946966947568625982967205345630645751953125, which rounds down, but the exact decimal value rounds up.