我有一个函数,它使用因子转换计数器值并将结果返回为无符号长整型。我需要处理可能的溢出。
IntVars.Counter_ui32:
IntVars.Factor_fl32(和结果局部变量)
一般来说,只要值有效并且返回 unsigned long 的其余部分,我不介意结果是否溢出 unsigned long 类型。因此,我假设我需要实现 math.h 的 fmod() 函数的替代方案,因为我无法使用库函数。
unsigned long Function(IntVars_ts IntVars)
{
float Result = (float) IntVars.Counter_ui32 * IntVars.Factor_fl32;
//Result = Result % (2^32-1); /* modulo works with integers only */
return (unsigned long) Result;
}
在这种情况下怎么办?我打算在 while 循环中减去 unsigned long max 值,但是正如您从输出中看到的那样,我迷失了两种不同类型的转换和可能的溢出。在这种情况下 float 没有足够的有效数字来表示 unsigned long 值吗?
注意:下面输出的最大数据类型值与我的目标平台中的不同(有效数字在上面)
从您的角度来看,还有什么需要担心的吗?如果我们只讨论丢失小数部分,则转换回 unsigned long 时的舍入错误在我的应用程序中不应成为问题。
/**************************
Online C Compiler.
Code, Compile, Run and Debug C program online.
Write your code in this editor and press "Run" button to compile and execute it.
***************************/
#include <stdio.h>
#include <float.h>
//#define UI32MAX ((unsigned long)4294967295UL)
#define UI32MAX ((unsigned long)18446744073709551615ul)
typedef struct
{
unsigned long counter;
float factor;
}IntVars_ts;
unsigned long Function(IntVars_ts IntVars);
int main()
{
unsigned long start = UI32MAX - 3ul;
printf("Maximum Unsigned Long %lu\n",(unsigned long)~0);
printf("Maximum float %f\n\n",FLT_MAX);
IntVars_ts IntVars ={start,1.0f}; /* Constant factor, I only increment the counter\
\in this example */
while(1)
{
printf("The unsigned long counter value is %lu\n",IntVars.counter);
printf("The float counter value is %f\n",(float)IntVars.counter);
printf("The result is %lu\n\n",Function(IntVars));
IntVars.counter++;
}
return 0;
}
unsigned long Function(IntVars_ts IntVars)
{
float Result = (float)IntVars.counter*IntVars.factor;
while(Result >= (float)UI32MAX)
{
printf("Result is %f\n",Result);
printf("Max is %f\n\n",(float)UI32MAX);
Result -= (float)UI32MAX;
}
return (unsigned long)Result;
}
Output of the previous code is following:
/tmp/z2jTCSG5B0.o
Maximum Unsigned Long 18446744073709551615
Maximum float 340282346638528859811704183484516925440.000000
The unsigned long counter value is 18446744073709551612
The float counter value is 18446744073709551616.000000
Result is 18446744073709551616.000000
Max is 18446744073709551616.000000
The result is 0
The unsigned long counter value is 18446744073709551613
The float counter value is 18446744073709551616.000000
Result is 18446744073709551616.000000
Max is 18446744073709551616.000000
The result is 0
The unsigned long counter value is 18446744073709551614
The float counter value is 18446744073709551616.000000
Result is 18446744073709551616.000000
Max is 18446744073709551616.000000
The result is 0
The unsigned long counter value is 18446744073709551615
The float counter value is 18446744073709551616.000000
Result is 18446744073709551616.000000
Max is 18446744073709551616.000000
The result is 0
The unsigned long counter value is 0
The float counter value is 0.000000
The result is 0
The unsigned long counter value is 1
The float counter value is 1.000000
The result is 1
The unsigned long counter value is 2
The float counter value is 2.000000
The result is 2
The unsigned long counter value is 3
The float counter value is 3.000000
The result is 3
一般来说,只要值有效并且返回 unsigned long 的其余部分,我不介意结果是否溢出 unsigned long 类型。因此,我假设我需要实现 math.h 的 fmod() 函数的替代方案,因为我无法使用库函数。
鉴于您的
long
是 32 位宽,并且 unsigned long long
必须至少为 64,计算中间 unsigned long long
(足够注意精度)是避免比例因子较大时出现溢出问题的相当好的方法比 1. 只需将该结果分配给类型 unsigned long
即可获得所需的模数缩减。但由于这一切都依赖于所涉及类型的大小,因此最好在这里使用标准显式精度整数类型。充分考虑精度可能意味着使用 double
: 类型执行缩放计算
#include <stdint.h>
uint32_t Function(IntVars_ts IntVars) {
double Result = (double) IntVars.counter * IntVars.factor;
// only needed if IntVars.factor exceeds ULONG_MAX:
double excess = (uint64_t) (Result / UINT64_MAX) * UINT64_MAX;
Result -= excess;
uint64_t integer_result = Result;
return integer_result;
}
但是请注意,当比例因子小于 1 时,您会遇到截断问题,而不是您所询问的溢出问题。如果对函数的连续调用返回不同的结果很重要,则上述方法不适合这种情况。