关于fmodf返回无效值

beyondlwm 2015-05-11 02:58:50
最近遇到一个随机出现的bug,请大家参考一下:
代码段(为了更详细的分析bug特意写成这样的):
float fTemp = 0;
BEATS_ASSERT(!isinf(m_fPlayingTime) && !isnan(m_fPlayingTime));
fTemp = fmodf(m_fPlayingTime, fDuration);
BEATS_ASSERT(!isinf(fTemp) && !isnan(fTemp));

问题:
第二个断言被引发,fTemp的值为-1.#IND000.
当时的上下文为:
m_fPlayingTime = 3.34924316
fDuration = 3.33333325

奇怪的地方:
因为assert引发以后,运行指针会停止在最后一句话上,我在vs2013里直接将该运行指针拉到上一句(即在上下文完全不变的情况下,重新执行fmodf),可以得到正确结果 fTemp = 0.0159099102

我的环境是WINDOWS7 + Vs2013, 没用使用多线程,该bug引发的几率也不高。

求指教。
...全文
326 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2015-06-01
  • 打赏
  • 举报
回复
我只负责提供解决楼主问题的思路或方法或操作步骤,不负责具体解决楼主的问题。
pengzhixi 2015-05-30
  • 打赏
  • 举报
回复
我个人怀疑是因为精度引起的。你使用fmod看看结果是什么?毕竟fmod的参数是double,精度高很多,你测试看看是什么情况
beyondlwm 2015-05-30
  • 打赏
  • 举报
回复
赵老师: 谢谢你耐心回答我的问题,并且贴了这么多资料 其实我的问题大概是 有时候 fmodf(5.0f, 2.0f) ==-1.#IND000 两个参数都是没问题的,返回的也是临时变量。 麻烦您再帮我看看: =====出bug时的上下文======= 第二个断言被引发,fTemp的值为-1.#IND000. 当时的上下文为: m_fPlayingTime = 3.34924316 fDuration = 3.33333325 =========================
beyondlwm 2015-05-18
  • 打赏
  • 举报
回复
谢谢赵老师 但是: 1. 这个bug不是100%出,而且按照数据更改次数来看几率的话,小到忽略不计.但是调用又非常频繁。 2. 没有用多线程,野指针也不太可能。硬中断这个,不太懂。 用data break point无法找到原因。更改太频繁,而且大部分时候得到的是正确的结果。
赵4老师 2015-05-18
  • 打赏
  • 举报
回复
Debugging Tools for Windows ba (Break on Access) The ba command sets a data breakpoint. This breakpoint is triggered when the specified memory is accessed. Syntax User-Mode [~Thread] ba[ID] Access Size [Options] [Address [Passes]] ["CommandString"] Kernel-Mode ba[ID] Access Size [Options] [Address [Passes]] ["CommandString"] Parameters Thread Specifies the thread that the breakpoint applies to. For more information about syntax, see Thread Syntax. You can specify threads only in user mode. ID Specifies an optional number that identifies the breakpoint. If you do not specify ID, the first available breakpoint number is used. You cannot add space between ba and the ID number. Each processor supports only a limited number of data breakpoints, but there is no restriction on the value of the ID number. If you enclose ID in square brackets ([]), ID can include any expression. For more information about the syntax, see Numerical Expression Syntax. Access Specifies the type of access that satisfies the breakpoint. This parameter can be one of the following values.Option Action e (execute) Breaks into the debugger when the CPU retrieves an instruction from the specified address. r (read/write) Breaks into the debugger when the CPU reads or writes at the specified address. w (write) Breaks into the debugger when the CPU writes at the specified address. i (i/o) (Microsoft Windows XP and later versions, kernel mode only, x86-based systems only) Breaks into the debugger when the I/O port at the specified Address is accessed. You cannot add space between Access and Size. Note On Windows Server 2003 with Service Pack 1 (SP1), on an Itanium-based computer that uses WOW64 to emulate x86, data breakpoints do not work with the execute option but they do work with the read and write options. Size Specifies the size of the location, in bytes, to monitor for access. On an x86-based processor, this parameter can be 1, 2, or 4. However, if Access equals e, Size must be 1. On an x64-based processor, this parameter can be 1, 2, 4, or 8. However, if Access equals e, Size must be 1. On an Itanium-based processor, this parameter can be any power of 2, from 1 to 0x80000000. You cannot add space between Access and Size. Options Specifies breakpoint options. You can use any number of the following options, except as indicated: /1 Creates a "one-shot" breakpoint. After this breakpoint is triggered, the breakpoint is permanently removed from the breakpoint list. /f PredNum (Itanium only, user mode only) Specifies a predicate number. The breakpoint is predicated with the corresponding predicate register (for example, bp /f 4 address sets a breakpoint that is predicated with the p4 predicate register). For more information about predicate registers, see Itanium Architecture. /p EProcess (Kernel mode only) Specifies a process that is associated with this breakpoint. EProcess should be the actual address of the EPROCESS structure, not the PID. The breakpoint is triggered only if it is encountered in the context of this process. /t EThread (Kernel mode only) Specifies a thread that is associated with this breakpoint. EThread should be the actual address of the ETHREAD structure, not the thread ID. The breakpoint is triggered only if it is encountered in the context of this thread. If you use /p EProcess and /t EThread , you can enter them in either order. /c MaxCallStackDepth Causes the breakpoint to be active only when the call stack depth is less than MaxCallStackDepth. You cannot combine this option together with /C. /C MinCallStackDepth Causes the breakpoint to be active only when the call stack depth is larger than MinCallStackDepth. You cannot combine this option together with /c. Address Specifies any valid address. If the application accesses memory at this address, the debugger stops execution and displays the current values of all registers and flags. This address must be an offset and suitably aligned to match the Size parameter. (For example, if Size is 4, Address must be a multiple of 4.) If you omit Address, the current instruction pointer is used. For more information about the syntax, see Address and Address Range Syntax. Passes Specifies the number of times the breakpoint is passed by until it activates. This number can be any 16-bit value. The number of times the program counter passes through this point without breaking is one less than the value of this number. Therefore, omitting this number is the same as setting it equal to 1. Note also that this number counts only the times that the application executes past this point. Stepping or tracing past this point does not count. After the full count is reached, you can reset this number only by clearing and resetting the breakpoint. CommandString Specifies a list of commands to execute every time that the breakpoint is encountered the specified number of times. These commands are executed only if the breakpoint is hit after you issue a g (Go) command, instead of after a t (Trace) or p (Step) command. Debugger commands in CommandString can include parameters. You must enclose this command string in quotation marks, and you should separate multiple commands by semicolons. You can use standard C control characters (such as \n and \"). Semicolons that are contained in second-level quotation marks (\") are interpreted as part of the embedded quoted string. This parameter is optional Environment Modes User mode, kernel mode Targets Live debugging only Platforms All Comments The debugger uses the ID number to refer to the breakpoint in later bc (Breakpoint Clear), bd (Breakpoint Disable), and be (Breakpoint Enable) commands. Use the bl (Breakpoint List) command to list all existing breakpoints, their ID numbers, and their status. Use the .bpcmds (Display Breakpoint Commands) command to list all existing breakpoints, their ID numbers, and the commands that were used to create them. The ba command provides the same functionality that the debug registers provide. You can break execution when the particular memory location is read from, written to, or executed. The breakpoint is satisfied only when the access occurs at the given address and for the specified number of bytes. If the memory that is accessed overlaps the specified area to monitor, the breakpoint is not satisfied. Although the size is required for all breakpoint types, an execute breakpoint is satisfied only if the address is the first byte in the instruction. When you debug a multiprocessor system in kernel mode, breakpoints that you set by using bp (Set Breakpoint) or ba apply to all processors. For example, if the current processor is 3 and you type ba e1 MemoryAddress to put a breakpoint at MemoryAddress, any processor (not only processor 3) that executes at that address causes a breakpoint trap. You cannot set the initial breakpoint in a user-mode process by using the ba command. You cannot create multiple breakpoints at the same address that differ only in their CommandString values. However, you can create multiple breakpoints at the same address that have different restrictions (for example, different values of the /p, /t, /c, and /C options). When you debug in kernel mode, the target computer distinguishes between user-mode and kernel-mode data breakpoints. A user-mode data breakpoint cannot affect kernel execution or memory access. A kernel-mode data breakpoint might affect user-mode execution or memory access, depending on whether the user-mode code is using the debug register state and whether there is a user-mode debugger that is attached. To apply the current process' existing data breakpoints to a different register context, use the .apply_dbp (Apply Data Breakpoint to Context) command. The following examples show the ba command. The following command sets a breakpoint for read access on 4 bytes of the variable myVar. 0:000> ba r4 myVar The following command adds a breakpoint on all serial ports with addresses from 0x3F8 through 0x3FB. This breakpoint is triggered if anything is read or written to these ports. kd> ba i4 3f8 Additional Information For more information about and examples of using breakpoints, other breakpoint commands and methods of controlling breakpoints, and information about how to set breakpoints in user space from a kernel debugger, see Using Breakpoints. For more information about conditional breakpoints, see Setting a Conditional Breakpoint. © 2009 Microsoft Corporation Send feedback on this topic Debugging Tools for Windows January 17, 2009 Build machine: CAPEBUILD Additional Information For more information about and examples of using breakpoints, other breakpoint commands and methods of controlling breakpoints, and information about how to set breakpoints in user space from a kernel debugger, see Using Breakpoints. For more information about conditional breakpoints, see Setting a Conditional Breakpoint.
赵4老师 2015-05-18
  • 打赏
  • 举报
回复
你会设置conditional data break point吗?
赵4老师 2015-05-15
  • 打赏
  • 举报
回复
引用 5 楼 beyondlwm 的回复:
我清楚fmod和fmodf的区别 但是这和我的问题无关啊。 我的问题是: 同样的代码,同样的上下文,执行两次结果会不一样。
也许你参加运算的两个变量的值在两次运算的时候被多线程、硬中断、野指针、……改变了。 To set a breakpoint when a variable changes value From the Edit menu, click Breakpoints. Click the Data tab of the Breakpoints dialog box. In the Expression text box, type the name of the variable. Click OK to set the breakpoint.
beyondlwm 2015-05-14
  • 打赏
  • 举报
回复
我清楚fmod和fmodf的区别 但是这和我的问题无关啊。 我的问题是: 同样的代码,同样的上下文,执行两次结果会不一样。
赵4老师 2015-05-12
  • 打赏
  • 举报
回复
VS IDE中,在不明白的符号fmodf上点鼠标右键,选转到定义。
赵4老师 2015-05-12
  • 打赏
  • 举报
回复
fmodf和fmod不是一回事。
beyondlwm 2015-05-11
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
fmod Calculates the floating-point remainder. double fmod( double x, double y ); Function Required Header Compatibility fmod <math.h> ANSI, Win 95, Win NT For additional compatibility information, see Compatibility in the Introduction. Libraries LIBC.LIB Single thread static library, retail version LIBCMT.LIB Multithread static library, retail version MSVCRT.LIB Import library for MSVCRT.DLL, retail version Return Value fmod returns the floating-point remainder of x / y. If the value of y is 0.0, fmod returns a quiet NaN. For information about representation of a quiet NaN by the printf family, see printf. Parameters x, y Floating-point values Remarks The fmod function calculates the floating-point remainder f of x / y such that x = i * y + f, where i is an integer, f has the same sign as x, and the absolute value of f is less than the absolute value of y. Example /* FMOD.C: This program displays a * floating-point remainder. */ #include <math.h> #include <stdio.h> void main( void ) { double w = -10.0, x = 3.0, y = 0.0, z; z = fmod( x, y ); printf( "The remainder of %.2f / %.2f is %f\n", w, x, z ); printf( "The remainder of %.2f / %.2f is %f\n", x, y, z ); } Output The remainder of -10.00 / 3.00 is -1.000000 Floating-Point Support Routines See Also ceil, fabs, floor
您好,赵老师,您的答复我在提问前已经读过了 既然您特意回复我一次,我又仔细的读了三遍,但是感觉仍然没有什么帮助。 能请您再多读一次我的问题么?
赵4老师 2015-05-11
  • 打赏
  • 举报
回复
fmod Calculates the floating-point remainder. double fmod( double x, double y ); Function Required Header Compatibility fmod <math.h> ANSI, Win 95, Win NT For additional compatibility information, see Compatibility in the Introduction. Libraries LIBC.LIB Single thread static library, retail version LIBCMT.LIB Multithread static library, retail version MSVCRT.LIB Import library for MSVCRT.DLL, retail version Return Value fmod returns the floating-point remainder of x / y. If the value of y is 0.0, fmod returns a quiet NaN. For information about representation of a quiet NaN by the printf family, see printf. Parameters x, y Floating-point values Remarks The fmod function calculates the floating-point remainder f of x / y such that x = i * y + f, where i is an integer, f has the same sign as x, and the absolute value of f is less than the absolute value of y. Example /* FMOD.C: This program displays a * floating-point remainder. */ #include <math.h> #include <stdio.h> void main( void ) { double w = -10.0, x = 3.0, y = 0.0, z; z = fmod( x, y ); printf( "The remainder of %.2f / %.2f is %f\n", w, x, z ); printf( "The remainder of %.2f / %.2f is %f\n", x, y, z ); } Output The remainder of -10.00 / 3.00 is -1.000000 Floating-Point Support Routines See Also ceil, fabs, floor

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧