gcc - C++ Decimal Floating Point Erroneous Rounding -
i seeing strange behavior when attempting use libdfp in c++ program. specifically, appears if gcc rounding 8 decimal places, when use 64- , 128-bit decimal types.
to test this, created incredibly simple test program:
std::decimal::decimal64 testval = 0.044575289999999997dd; printf("decimal float test: expected=0.044575289999999997, actual=%.16da\n", testval);
which outputs:
decimal float test: expected=0.044575289999999997, actual=0.04457529000000000
i not printing problem in libdfp able trace source , found number rounded first line of printf handler. additionally, printf handler round, have verified code not being called.
for reference, building libdfp with:
./configure --with-backend=libdecnumber --enable-decimal-float=bid && make
i suspect problem either in underlying decimal float representation (bid, in case) or raw types being provided gcc. looks if being rounded size of 32-bit decimal float. host arch x86_64 should supported natively. furthermore, gcc have corresponding _decimal[32|64|128]
types , <decimal/decimal>
can found on system. building on fedora 25 native x86_64 cpu (intel xenon). afaik, processor not have native decimal float support being rendered in software.
the clue have gcc not list --enable-decimal-float
build option in configuration summary:
$ g++ -v using built-in specs. collect_gcc=g++ collect_lto_wrapper=/usr/libexec/gcc/x86_64-redhat-linux/6.3.1/lto-wrapper target: x86_64-redhat-linux configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux thread model: posix gcc version 6.3.1 20161221 (red hat 6.3.1-1) (gcc) $ g++ --version g++ (gcc) 6.3.1 20161221 (red hat 6.3.1-1) copyright (c) 2016 free software foundation, inc. free software; see source copying conditions. there no warranty; not merchantability or fitness particular purpose.
that being said, compiler does define _decimal[32|64|128]
types , provides operator<< overloads them. wouldn't expect these available @ if such support not enabled. shouldn't able compile program using them , almost valid output back.
finally, see being problem libdecnumber @ limit of current knowledge manages assignment these types.
has seen issue before? failing that, has build , used libdfp on similar setup? piece of software controls rounding internal representation (as opposed rounding display)?
edit
i managed disassembly. appears full value being loaded rdx
, decimal64
constructor called. value 0x2fafd619589efa00
works out 3436200445056317952
in decimal, suspect 0.044575289999999997
represented in bid format. not sure how gcc knows used bid vs dpd specified @ libfdp build time, leave particular mystery post.
if understanding correct, seems imply gcc doing rounding. there can done other rebuilding compiler (which avoid)? know ieee-754 provides mechanisms 'tune' behavior of fp operations (including rounding mode), gcc expose of user?
disassembly
│0x401180 <main(int, char**)> push rbp │ │0x401181 <main(int, char**)+1> mov rbp,rsp │ │0x401184 <main(int, char**)+4> sub rsp,0x30 │ │0x401188 <main(int, char**)+8> mov dword ptr [rbp-0x14],edi │ │0x40118b <main(int, char**)+11> mov qword ptr [rbp-0x20],rsi │ b+ │0x40118f <main(int, char**)+15> movabs rdx,0x2fafd619589efa00 │ │0x401199 <main(int, char**)+25> lea rax,[rbp-0x10] │ │0x40119d <main(int, char**)+29> mov qword ptr [rbp-0x28],rdx │ │0x4011a1 <main(int, char**)+33> movq xmm0,qword ptr [rbp-0x28] │ │0x4011a6 <main(int, char**)+38> mov rdi,rax │ │0x4011a9 <main(int, char**)+41> call 0x4012e6 <std::decimal::decimal64::decimal64(decimal64)> │ │0x4011ae <main(int, char**)+46> mov rax,qword ptr [rbp-0x10] │ │0x4011b2 <main(int, char**)+50> mov qword ptr [rbp-0x28],rax │ │0x4011b6 <main(int, char**)+54> movq xmm0,qword ptr [rbp-0x28] │ │0x4011bb <main(int, char**)+59> mov edi,0x4018e8 │ │0x4011c0 <main(int, char**)+64> mov eax,0x1 │ │0x4011c5 <main(int, char**)+69> call 0x400a30 <printf@plt> │ │0x4011ca <main(int, char**)+74> mov eax,0x0 │ │0x4011cf <main(int, char**)+79> leave │ │0x4011d0 <main(int, char**)+80> ret │ │0x4011d1 <__static_initialization_and_destruction_0(int, int)> push rbp │ │0x4011d2 <__static_initialization_and_destruction_0(int, int)+1> mov rbp,rsp │ │0x4011d5 <__static_initialization_and_destruction_0(int, int)+4>────────sub rsp,0x10───────────────────────────────────────────────────────────│ │0x4011d9 <__static_initialization_and_destruction_0(int, int)+8> mov dword ptr [rbp-0x4],edi │ │0x4011dc <__static_initialization_and_destruction_0(int, int)+11> mov dword ptr [rbp-0x8],esi │ │0x4011df <__static_initialization_and_destruction_0(int, int)+14> cmp dword ptr [rbp-0x4],0x1 │ │0x4011e3 <__static_initialization_and_destruction_0(int, int)+18> jne 0x40120c <__static_initialization_and_destruction_0(int, int)+59> │ │0x4011e5 <__static_initialization_and_destruction_0(int, int)+20> cmp dword ptr [rbp-0x8],0xffff │ │0x4011ec <__static_initialization_and_destruction_0(int, int)+27> jne 0x40120c <__static_initialization_and_destruction_0(int, int)+59> │ │0x4011e5 <__static_initialization_and_destruction_0(int, int)+20> cmp dword ptr [rbp-0x8],0xffff │ │0x4011ec <__static_initialization_and_destruction_0(int, int)+27> jne 0x40120c <__static_initialization_and_destruction_0(int, int)+59> │ │0x4011ee <__static_initialization_and_destruction_0(int, int)+29> mov edi,0x60309d │ │0x4011f3 <__static_initialization_and_destruction_0(int, int)+34> call 0x400ae0 <_znst8ios_base4initc1ev@plt> │ │0x4011f8 <__static_initialization_and_destruction_0(int, int)+39> mov edx,0x4018d8 │ │0x4011fd <__static_initialization_and_destruction_0(int, int)+44> mov esi,0x60309d │ │0x401202 <__static_initialization_and_destruction_0(int, int)+49> mov edi,0x400aa0 │ │0x401207 <__static_initialization_and_destruction_0(int, int)+54> call 0x400ac0 <__cxa_atexit@plt> │
complete test source
#include <float.h> #include <decimal/decimal> #include <math.h> #include <fenv.h> #include <stdlib.h> #include <wchar.h> #include <cstdlib> int main (int argc, char *argv[]) { std::decimal::decimal64 testval = 0.044575289999999997dd; printf("decimal float test: expected=0.044575289999999997, actual=%.16da\n", testval); return exit_success; }
Comments
Post a Comment