views:

203

answers:

6

I am doing some custom serializing, and in order to save some space, i want to serialize the decimals as int, if possible value wise. Performance is a concern, since i am dealing with a high volume of data. The current method i use is:

if ((value > Int32.MinValue) && (value < Int32.MaxValue) && ((valueAsInt = Decimal.ToInt32(value)) == value))
{
    return true;
}

Can this be improved?

+1  A: 

Your invalidation criteria are:

1) Is it greater than MaxValue?

2) Is it smaller than MinValue?

3) Does it contain a fractional component?

It sounds like you have them covered. My implementation would be:

public bool IsConvertibleToInt(decimal value)
{
    if(value > int.MaxValue)
       return false;

    if(value < int.MinValue)
       return false;

    if(Math.Floor(value) < value && Math.Ceiling(value) > value)
       return false;

    return true;
}
Tejs
My solution works, i was wondering if it can be sped up. Thanks
anchandra
A: 

Wouldn't you be able to just do something like:

if(Decimal.ToInt32(value) == value)
{
     return true;
}

Not an expert on .net, but I think that should be all it'd require. Also, your two comparisons operators should be 'or equal' since the min/max values are also valid.

Edit: As pointed out in the comment, this would throw an exception. You could try catching the exception and returning false, but at that point it likely would be much faster to do the min/max testing yourself.

Kitsune
@Kitsune: This throws an exception if value is too large.
RedFilter
@Kitsune: It is a problem of performance, not of functionality. My current solution works properly, but i want to see if i can improve its performance
anchandra
@anchandra: Yeah, that's why I didn't really recommend doing that instead, since it'd likely be slower and probably not be any more readable.
Kitsune
+1  A: 

How about this. I think it should take fewer operations (at least a fewer number of comparisons):

    return (value == (Int32)value);

Also remember, if an if statement simply returns a boolean, you can just return the comparison. That alone might make it faster (unless the compiler already optimizes for this). If you have to use the if statement, you can similarly do this:

    if (value == (Int32)value)
    {
        //Do stuff...
    return true;
    }
    else
    {
        //Do stuff...
        return false;
    }

EDIT: I realize this doesn't actually work. I was thinking the Int32 cast would just copy in the first 32 bits from the decimal, leaving behind any remaining bits (and not throw an exception), but alas, it didn't work that way (not to mention it would be wrong for all negative values).

smoore
@smoore: This throws an exception if value is too large.
RedFilter
Damn, you're right!
smoore
@OrbMan: Would unsafe do the trick and force explicit casting?
smoore
@smoore - I think you mean "unchecked", but no the checked vs. unchecked context doesn't affect operations on decimal.
Jeffrey L Whitledge
There is not performance improvement between value ==(int32)value and decimal.toint32. I disassembled the decimal class, and the explicit operator for int looks like this:public static explicit operator int(Decimal value) { return ToInt32(value); }
anchandra
@anchandra: The performance improvement came from only one comparison instead of three (which would def be an improvement), but it didn't work anyways, so it doesn't really matter.
smoore
A: 

No need for "valueAsInt =". I believe (Decimal.ToInt32(value) == value)) gets you the same result with one less assignment. Are you using valueAsInt as some sort of output parameter?

CuriousCoder
I need it as an output param, but the question is if i can determine the int value in a more efficient way
anchandra
+1  A: 

It depends on how many decimal places you have or really care about. If you could say that I only care about up to 3 decimal places then the largest number you can store in int32 is int.MaxValue / 1000. If you are only working with positive numbers then you can get a higher number by using uint. In any case the way to do it is to consistently reserve space for the decimal and use * 1000 to encode them and / 1000 to decode them to / from decimal.

Nate Zaugg
I cannot put limit on precision, unfortunately
anchandra
+1  A: 

Do you have any negative values? I'm guessing yes since you have the MinValue check, otherwise you can skip it. You could even use unsigned int which will allow you to convert more of your double values into ints.

Edit: Also, if you have more positive numbers, you can swap the first two conditions. That way the first one is the most likely to fail, decreasing the total number of comparisons.

Nelson
I can have any values, with any number of decimals. Precision is a big concern
anchandra
That is actually a very good point. I will investigate this aspect. Thanks
anchandra
Depending on the nature of your numbers/requirements, you could also consider using short, int and long, or even double and float (but be careful with loss of precision). The conversion would take longer since you would have to determine the optimal type, but it would save on space. If your bottleneck is space or transmission speed (e.g. slow internet connection) and not CPU, this may be viable.
Nelson