确定一个十进制数是否可以存储为int32

4

我正在进行一些自定义序列化操作,为了节省空间,如果可能的话,我希望将小数序列化为整数。由于我正在处理大量数据,因此性能是一个问题。我目前使用的方法是:

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

这个能不能改进?


你一直在谈论性能,但我没有看到任何基准测试或具体要求。你怎么知道这种方法的表现不够好?你期望看到多大的改进?你如何知道是否已经实现了它? - Aaronaught
@aaronaught 我并不是说这个方法表现得不够好,但这并不意味着它不能更加高效。对于我的数据量,在序列化和分析发生的情况时,这段代码花费了 4% 的 CPU 时间。任何更少的时间都是一种进步。话虽如此,我并不是一个内部数字表示或 IL 执行方面的专家,因此由于我在这个领域的知识不足,可能还有提高的空间。 - anchandra
"性能"也可以通过运行所需时间来衡量。如果仅占用4%的CPU,您可以尝试使用多线程来利用更多CPU资源,以更快地完成任务。或者我是否误解了,实际上该代码只是从总CPU使用率中占用了4%(可能接近100%)? - Nelson Rothermel
我对整个序列化过程的CPU使用百分比很感兴趣。 - anchandra
@anchandra:这就是所谓的过早优化。很可能这种方法的影响微乎其微,而4%的节省(或者其他数值)几乎没有什么明显的影响。当性能真正成为问题时,我完全支持关于性能优化的问题,但是“优化”两个算术比较并不是一个非常有用的练习。我们实际上只谈论了大约20个CPU指令;如果您必须处理10亿个值,那么这种节省将转化为10秒钟中的1秒钟。比首先生成数据所需的时间还要短。 - Aaronaught
1
@Aaronaught 我不明白为什么这是一个无用的练习。它涉及理解数字表示的内部结构,并选择在此基础上选择最有效的方式。例如,我可以通过将其转换为字符串并在字符串中检查小数点来实现此目的。它可以工作,但不是最佳解决方案。这就是我在问题中没有给出性能细节的原因。当前代码已经足够高效并且正在生产中使用,所以这不是关于过早优化,而是关于好奇心和自我提高。 - anchandra
6个回答

1

你的无效条件如下:

1)它是否大于最大值?

2)它是否小于最小值?

3)它是否包含小数部分?

听起来你已经考虑到了这些情况。我的实现将是:

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;
}

我的解决方案可以工作,我想知道它是否可以加速。谢谢。 - anchandra

1
这样怎么样?我认为它应该需要更少的操作(至少需要更少的比较):
    return (value == (Int32)value);

还要记住,如果一个 if 语句仅返回一个布尔值,你可以直接返回比较结果。这样可能会使代码更快(除非编译器已经对此进行了优化)。如果你必须使用 if 语句,也可以类似地这样写:

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

编辑:我意识到这实际上并不起作用。我认为Int32转换将只复制十进制数的前32位,留下任何剩余的位(而不会抛出异常),但是不幸的是,它并没有按照我想象的方式工作(更不用说对于所有负值都是错误的)。


1
@smoore:如果值太大,这会抛出一个异常。 - D'Arcy Rittich
@OrbMan:使用unsafe关键字是否可以达到目的并强制进行显式转换? - Seth Moore
@smoore - 我想你的意思是“未经检查的”,但是检查与未检查的上下文并不影响十进制操作。 - Jeffrey L Whitledge
在value ==(int32)value和decimal.toint32之间没有性能提升。我反汇编了decimal类,int的显式运算符看起来像这样: public static explicit operator int(Decimal value) { return ToInt32(value); } - anchandra
@anchandra:性能的提升只来自于一次比较而不是三次(这肯定是一种改进),但它仍然无法正常工作,所以并不重要。 - Seth Moore

1

这取决于你有多少小数位或者你真正关心的是多少。如果你只关心最多3位小数,那么在int32中可以存储的最大数字是int.MaxValue / 1000。如果你只处理正数,那么使用uint可以得到更高的数字。无论如何,做法是始终为小数保留空间,并使用* 1000进行编码和/ 1000进行解码以转换为/从十进制。


我很遗憾无法限制精度。 - anchandra

1

你有任何负数吗?我猜想是的,因为你有MinValue检查,否则你可以跳过它。你甚至可以使用无符号整型,这将允许您将更多的双精度值转换为整数。

编辑:此外,如果您有更多正数,则可以交换前两个条件。这样第一个条件最可能失败,从而减少总比较次数。


我可以拥有任何值,带有任意数量的小数。精度是一个重要问题。 - anchandra
那是一个非常好的观点。我会调查这个方面。谢谢。 - anchandra
根据你的数字/需求的性质,你也可以考虑使用short、int和long,甚至double和float(但要小心精度损失)。转换需要更长时间,因为你必须确定最佳类型,但它可以节省空间。如果瓶颈是空间或传输速度(例如,慢的互联网连接),而不是CPU,那么这可能是可行的。 - Nelson Rothermel

0

你不是可以做类似这样的事情吗:

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

虽然我不是 .net 的专家,但我认为那应该就是所需的全部。此外,你的两个比较运算符应该是“或等于”,因为最小/最大值也是有效的。

编辑:正如评论中指出的那样,这会抛出异常。你可以尝试捕获异常并返回 false,但此时自己进行最小/最大值测试可能会更快。


1
@Kitsune:如果值太大,这将抛出一个异常。 - D'Arcy Rittich
@Kitsune:这是一个性能问题,而不是功能问题。我的当前解决方案可以正常工作,但我想看看是否可以提高其性能。 - anchandra
@anchandra:是的,这就是为什么我并没有真正推荐这样做,因为它很可能会更慢,而且可能不会更易读。 - Kitsune

0

不需要 "valueAsInt ="。我相信 (Decimal.ToInt32(value) == value)) 可以得到相同的结果,而且少了一个赋值。你是把 valueAsInt 用作某种输出参数吗?


我需要它作为输出参数,但问题是我是否可以以更有效的方式确定int值。 - anchandra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接