使用复杂的位掩码确定哪个位设置为某个日期

我有一个移位掩码,代表一周内的几天:

Sunday = 1
Monday = 2
Tuesday = 4
...
Saturday = 64

我正在使用位掩码,因为几天(至少一天)可能会设置为1。

问题

然后我得到一个约会。 任何日期。 根据date.DayOfWeek我需要返回位掩码中设置的第一个最接近的日期。 所以我的方法可以返回datedate + 6之间的同一天或任何其他date + 6

例1

我的位掩码定义了所有日期设置为1.在这种情况下,我的方法应该返回相同的日期,因为date.DayOfWeek设置date.DayOfWeek掩码中。

例2

我的位掩码定义只有星期三设置为1.如果我的传入日期是星期二,我应该返回date+1 (即星期三)。 但是如果传入日期是星期四,我应该返回date+6 (这又是星期三)。

解决这个问题最快和最优雅的方法是什么? 为什么最快? 因为我需要运行几次,所以如果我可以使用某种缓存结构来更快地获取日期,那么这将是首选。

你能提出一些指导方案来解决这个问题吗? 我不想结束一个充满ifs和switch-case语句的冗长的意大利面条代码......

重要提示 :需要注意的是,如果掩码有助于提高性能和简化代码,则可能会更改掩码或将其替换为其他内容。 所以位掩码不是一成不变的...

一种可能的方法

每天生成一组偏移量并将其保存在私有类变量中会很明智。 生成一次,然后重新使用它,如下所示:

return date.AddDays(cachedDayOffsets[date.DayOfWeek]);

这样我们根本不使用位掩码,唯一的问题是如何以最快的速度和尽可能短的代码生成数组。


你可能讨厌这个答案,但也许你可以在一个新的方向上运行它。 你说性能是非常重要的,所以也许最好是在一些数据结构中索引所有的答案。 这个数据结构可能有点复杂,但它可以封装在自己的小世界中,不会干扰你的主代码。 我想到的数据结构将是一系列整数。 如果您允许星期一,星期五和星期六,这些整数将是:

[1][0][3][2][1][0][0]

好吧奇怪的权利? 这基本上是本周的“天数”列表。 星期天,“下一个星期允许一天”。 星期一,星期二有3天。 现在,一旦你建立了这个列表,你可以很容易,很快地找出你需要添加多少天来获得下一次发生。 希望这有助于?

生成这些偏移量

这是生成这些偏移量的代码:

this.dayOffsets = new int[] {
    this.Sundays ? 0 : this.Mondays ? 1 : this.Tuesdays ? 2 : this.Wednesdays ? 3 : this.Thursdays ? 4 : this.Fridays ? 5 : 6,
    this.Mondays ? 0 : this.Tuesdays ? 1 : this.Wednesdays ? 2 : this.Thursdays ? 3 : this.Fridays ? 4 : this.Saturdays ? 5 : 6,
    this.Tuesdays ? 0 : this.Wednesdays ? 1 : this.Thursdays ? 2 : this.Fridays ? 3 : this.Saturdays ? 4 : this.Sundays ? 5 : 6,
    this.Wednesdays ? 0 : this.Thursdays ? 1 : this.Fridays ? 2 : this.Saturdays ? 3 : this.Sundays ? 4 : this.Mondays ? 5 : 6,
    this.Thursdays ? 0 : this.Fridays ? 1 : this.Saturdays ? 2 : this.Sundays ? 3 : this.Mondays ? 4 : this.Tuesdays ? 5 : 6,
    this.Fridays ? 0 : this.Saturdays ? 1 : this.Sundays ? 2 : this.Mondays ? 3 : this.Tuesdays ? 4 : this.Wednesdays ? 5 : 6,
    this.Saturdays ? 0 : this.Sundays ? 1 : this.Mondays ? 2 : this.Tuesdays ? 3 : this.Wednesdays ? 4 : this.Thursdays ? 5 : 6
};

这一个产生前向偏移。 因此,对于任何给定的日期,您可以简单地通过以下方式获得实际适用日期:

SomeDate.AddDays(this.dayOffsets[(int)SomeDate.DayOfWeek]);

如果您需要取得最近的过去日期,则可以重新使用相同的数组并使用以下公式进行计算:

SomeDate.AddDays((this.dayOffsets[(int)SomeDate.DayOfWeek] - 7) % 7);

我会用一个掩码,一些移位和一个位扫描来解决这个问题。 这不是一个非常明显的例程,但它应该很快,因为它从不分支:

original_date = Whatever                    //user input
bitmask = Whatever                          //user input
bitmask |= (bitmask << 7)                   //copy some bits so they don't get
                                            //lost in the bitshift
bitmask >>= original_date.dayOfWeek()       //assuming Sunday.dayOfWeek() == 0
return original_date + bitscan(bitmask) - 1 //the position of the least
                                            //significant bit will be one greater
                                            //than the number of days to add

Bitscan--特别是你的,因为它只关心七位 - 很容易在查找表中实现。 事实上,如果您创建了自定义表格,则可以调用LSB位0,并在return语句中跳过减法。 我猜想所有这些中最慢的部分是dayOfWeek()函数,但这取决于它的实现。

希望这可以帮助!

编辑:示例bitscan表(将lsb视为索引1 - 您可能希望将其视为零,但这是一个更好的示例):

int[128] lsb = {
    0, //0 = 0b00000000 - Special case!
    1, //1 = 0b00000001
    2, //2 = 0b00000010
    1, //3 = 0b00000011
    3, //4 = 0b00000100
    1, //5 = 0b00000101
    2, //6 = 0b00000110
    ....
    1 //127 = 0b01111111
};

然后,要在mask上使用您的桌子,您只需使用:

first_bit_index = lsb[mask & 127];

&让你写一个短小的表,因为你真正关心的七个最低位。

PS:至少有一些处理器实现了一个你可以用来代替的bitscan指令,但是除非有一个包装器函数,否则你不可能用C#来获取它们。


这是我会做的,变量dateDiff将是你正在寻找的。

DoW mask      = DoW.Wednesday | DoW.Friday;
DoW? todayDoW = null;
int dateDiff  = 0;

do
{
    DateTime date = DateTime.Today.AddDays(dateDiff);
    todayDoW      = (DoW)Enum.Parse(typeof(DoW), date.DayOfWeek.ToString());

    if ((mask & todayDoW.Value) != 0)
    {
        todayDoW = null;
    }
    else
    {
        dateDiff++;
    }

}
while(todayDoW.HasValue);

enum DoW
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64
}
链接地址: http://www.djcxy.com/p/9343.html

上一篇: Determine which bit is set, for a date, using complex bit masks

下一篇: Is it possible to attach a debugger to a running PHP process?