Excel 单元格公式:比较计算值与手动输入时间值的间歇性错误
Excel Cell Formula: Intermittent Error Comparing Calculated vs. Manually Entered Time Values
注意:我已经通过 Whosebug 上列出的几种不同方法多次验证这些单元格包含的值不是文本!
我正在尝试编写一个日程安排工作簿,它可以告诉我当前的人员配置是否足够。有一个时间表 sheet 每个员工的打卡时间、第一次下班、第一次打卡、午餐外出、午餐上班、第二次下班、第二次打卡、下班打卡,这八个(8) 列重复七次 (x7) 以说明一周中的每一天。还有另一个 "analysis" 价差 sheet 从星期一的 6:30 AM - 6:45 AM 到 5:45 PM - [= 每行有 15 分钟的增量73=]周日下午。
在分析 sheet 时,我尝试使用不同的公式将块开始和块结束时间增加 15 分钟,然后填写以说明这 7 天的每个块。我记得尝试的公式如下,假设我在单元格 B2 中手动输入 6:30 AM:
=B2+(15/60/24)
=TRUNC(B2+TIME(0,15,0),12)
当我尝试比较员工的预定开始时间是否大于或等于块的开始时间,以及当我尝试比较员工的预定结束时间是否大于或等于时,问题变得特别痛苦等于块的结束时间。我相信这是由于计算时间的序列值与手动输入的计划时间的序列值之间存在微小的毫秒差异。但是,目标是 运行 通过 =COUNTIFS() 公式来确定在该时间段内在场的员工总数。到目前为止,我想出的公式看起来像这样(请忽略列引用,因为我将它复制了几列以便能够在第一列中尝试其他一些方法):
=COUNTIFS(OFFSET('Front Desk'!$B:$B,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$B:$B,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<="&'Front Desk Analysis'!H2,OFFSET('Front Desk'!$C:$C,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$C:$C,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),">="&'Front Desk Analysis'!L2)+COUNTIFS(OFFSET('Front Desk'!$D:$D,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$D:$D,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<="&'Front Desk Analysis'!H2,OFFSET('Front Desk'!$E:$E,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$E:$E,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),">="&'Front Desk Analysis'!L2)+COUNTIFS(OFFSET('Front Desk'!$F:$F,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$F:$F,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<="&'Front Desk Analysis'!H2,OFFSET('Front Desk'!$G:$G,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$G:$G,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),">="&'Front Desk Analysis'!L2)
请耐心等待我的长度和重复性,因为我试图解释四个间隔中的任何一个(打卡 - 第一次休息,第一次休息 - 午餐外出,午餐 - 第二次休息,以及第二次闯入 - 下班)。我认为有必要公开该功能的长度,并且它会变得更长,因为我需要考虑到一些可能会或可能不会休息的员工 and/or 一整天的午餐时间(想象一下有人有 2 到 4小时班只会打卡进出一次)。如果我开始在其中添加一大堆复杂的嵌套 ROUND() 函数,我担心会达到函数限制。
如果要我总结这个问题,我想我有四个问题:
- 为什么 9:30 AM 和 10:30 AM 的序列表示中的第 15 位十进制数字与手动输入时间的序列值相差一 (1),但十进制扩展两者的区别不? (0.395833333333334000000 - 0.395833333333333000000 = 0.000000000000000000000)
- 既然两个值之间的差值显然为零,为什么比较结果为假?
- 如果您要论证这是一个浮点计算问题,为什么不进行更少的 TRUE 比较(因为每个计算值都是根据先前的值计算得出的差值)所有后续值)使该结果成为例外而不是规范?
- 与最后三个略有不同,但这种方法是否与您用来解决整体调度问题的方法相似,或者您建议如何解决该问题?
我对这些问题中的每一个问题的答案都同样感兴趣,所以请随时回复其中一个或所有问题(请在回复中注明相关问题#)。提前谢谢大家!
编辑:我刚开始在这里询问有关堆栈溢出的问题,但我相信如果您按照以下步骤操作,可以创建一个最小的可重现示例:
- 在单元格 B2 中键入“6:30 AM”+ 输入键。
- 在单元格 B3 中键入“=B2+(15/60/24)”+ 输入键。
- 单击格式刷按钮,然后单击单元格 B2,然后单击单元格 B3(如果正确执行了第 1 步,则将公式单元格格式化为时间,否则从格式下拉列表中单击常规,然后单击时间)。
- Select 单元格 B3,然后向下拖动直到公式等于 9:30 AM 或更大。
- 键入“9:30 AM” + 在与还包含值“9:30 AM”的 B 列单元格相邻的 C 列单元格中输入键 + Enter 键(应为第 14 行 I相信)。
- 在与这些单元格右侧相邻的 D 列单元格中键入此公式:
=B14=C14
+ Enter 键,您应该得到 FALSE
评估。
您 运行 直面 Excel 的 data/time 系统的老问题,如您所知,该系统依赖于不准确的浮点数学运算。
解决方案一直是四舍五入到避免错误的幅度:
=ROUND(B5,7)
以上将时间值四舍五入到秒,允许接近的值相等,一秒的精度对于员工排班和工资单应该足够准确。
现在在公式中一遍又一遍地使用大量 ROUND() 函数远非理想。
有几种解决方法,但都不理想。
1.) 有一个 sheet 可以复制您的源数据,但是通过对每个相应的数据点使用 ROUND() 函数。在这种情况下,您会将您的 COUNTIFS() 公式瞄准这个中介 sheet。这使您不必在每个 COUNTIFS() 中无数次地使用 ROUND()。确实 ROUND() 仍在每个数据点上使用......但它只对每个数据点使用一次。
2.) 利用 VBA 进行计算,return 将结果用于分析 sheet。这甚至可以配置为用户定义函数 (UDF),您可以直接从分析中调用 sheet 作为公式。
注意:我已经通过 Whosebug 上列出的几种不同方法多次验证这些单元格包含的值不是文本!
我正在尝试编写一个日程安排工作簿,它可以告诉我当前的人员配置是否足够。有一个时间表 sheet 每个员工的打卡时间、第一次下班、第一次打卡、午餐外出、午餐上班、第二次下班、第二次打卡、下班打卡,这八个(8) 列重复七次 (x7) 以说明一周中的每一天。还有另一个 "analysis" 价差 sheet 从星期一的 6:30 AM - 6:45 AM 到 5:45 PM - [= 每行有 15 分钟的增量73=]周日下午。
在分析 sheet 时,我尝试使用不同的公式将块开始和块结束时间增加 15 分钟,然后填写以说明这 7 天的每个块。我记得尝试的公式如下,假设我在单元格 B2 中手动输入 6:30 AM:
=B2+(15/60/24)
=TRUNC(B2+TIME(0,15,0),12)
当我尝试比较员工的预定开始时间是否大于或等于块的开始时间,以及当我尝试比较员工的预定结束时间是否大于或等于时,问题变得特别痛苦等于块的结束时间。我相信这是由于计算时间的序列值与手动输入的计划时间的序列值之间存在微小的毫秒差异。但是,目标是 运行 通过 =COUNTIFS() 公式来确定在该时间段内在场的员工总数。到目前为止,我想出的公式看起来像这样(请忽略列引用,因为我将它复制了几列以便能够在第一列中尝试其他一些方法):
=COUNTIFS(OFFSET('Front Desk'!$B:$B,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$B:$B,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<="&'Front Desk Analysis'!H2,OFFSET('Front Desk'!$C:$C,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$C:$C,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),">="&'Front Desk Analysis'!L2)+COUNTIFS(OFFSET('Front Desk'!$D:$D,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$D:$D,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<="&'Front Desk Analysis'!H2,OFFSET('Front Desk'!$E:$E,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$E:$E,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),">="&'Front Desk Analysis'!L2)+COUNTIFS(OFFSET('Front Desk'!$F:$F,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$F:$F,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<="&'Front Desk Analysis'!H2,OFFSET('Front Desk'!$G:$G,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),"<>",OFFSET('Front Desk'!$G:$G,0,(MATCH(A2,'Front Desk'!$B:$BE,0)-1)),">="&'Front Desk Analysis'!L2)
请耐心等待我的长度和重复性,因为我试图解释四个间隔中的任何一个(打卡 - 第一次休息,第一次休息 - 午餐外出,午餐 - 第二次休息,以及第二次闯入 - 下班)。我认为有必要公开该功能的长度,并且它会变得更长,因为我需要考虑到一些可能会或可能不会休息的员工 and/or 一整天的午餐时间(想象一下有人有 2 到 4小时班只会打卡进出一次)。如果我开始在其中添加一大堆复杂的嵌套 ROUND() 函数,我担心会达到函数限制。
如果要我总结这个问题,我想我有四个问题:
- 为什么 9:30 AM 和 10:30 AM 的序列表示中的第 15 位十进制数字与手动输入时间的序列值相差一 (1),但十进制扩展两者的区别不? (0.395833333333334000000 - 0.395833333333333000000 = 0.000000000000000000000)
- 既然两个值之间的差值显然为零,为什么比较结果为假?
- 如果您要论证这是一个浮点计算问题,为什么不进行更少的 TRUE 比较(因为每个计算值都是根据先前的值计算得出的差值)所有后续值)使该结果成为例外而不是规范?
- 与最后三个略有不同,但这种方法是否与您用来解决整体调度问题的方法相似,或者您建议如何解决该问题?
我对这些问题中的每一个问题的答案都同样感兴趣,所以请随时回复其中一个或所有问题(请在回复中注明相关问题#)。提前谢谢大家!
编辑:我刚开始在这里询问有关堆栈溢出的问题,但我相信如果您按照以下步骤操作,可以创建一个最小的可重现示例:
- 在单元格 B2 中键入“6:30 AM”+ 输入键。
- 在单元格 B3 中键入“=B2+(15/60/24)”+ 输入键。
- 单击格式刷按钮,然后单击单元格 B2,然后单击单元格 B3(如果正确执行了第 1 步,则将公式单元格格式化为时间,否则从格式下拉列表中单击常规,然后单击时间)。
- Select 单元格 B3,然后向下拖动直到公式等于 9:30 AM 或更大。
- 键入“9:30 AM” + 在与还包含值“9:30 AM”的 B 列单元格相邻的 C 列单元格中输入键 + Enter 键(应为第 14 行 I相信)。
- 在与这些单元格右侧相邻的 D 列单元格中键入此公式:
=B14=C14
+ Enter 键,您应该得到FALSE
评估。
您 运行 直面 Excel 的 data/time 系统的老问题,如您所知,该系统依赖于不准确的浮点数学运算。
解决方案一直是四舍五入到避免错误的幅度:
=ROUND(B5,7)
以上将时间值四舍五入到秒,允许接近的值相等,一秒的精度对于员工排班和工资单应该足够准确。
现在在公式中一遍又一遍地使用大量 ROUND() 函数远非理想。
有几种解决方法,但都不理想。
1.) 有一个 sheet 可以复制您的源数据,但是通过对每个相应的数据点使用 ROUND() 函数。在这种情况下,您会将您的 COUNTIFS() 公式瞄准这个中介 sheet。这使您不必在每个 COUNTIFS() 中无数次地使用 ROUND()。确实 ROUND() 仍在每个数据点上使用......但它只对每个数据点使用一次。
2.) 利用 VBA 进行计算,return 将结果用于分析 sheet。这甚至可以配置为用户定义函数 (UDF),您可以直接从分析中调用 sheet 作为公式。