Cant make value propagate through carry

匿名 (未验证) 提交于 2019-12-03 01:27:01

问题:

Making a little C++ large precision class, and everything seems to work decent, but the add, if I add 0xffffffff and 0x04 together I get 0xffff0003 when I should get 0x0100000003. Here is the function with the issue:

mpfl operator+(const mpfl &lhs, const mpfl &rhs) {     unsigned long i;     mpfl ret(0);     mpfl trhs(rhs);     for (i = lhs.nbytes; i >= 0; i--)     {         if (             (unsigned short)lhs.data[i].data + (unsigned short)trhs.data[i].data             > (unsigned short)255         ) {             if (i > 0)             {                 ret.data[i].carry = 1;                 ret.data[0].carry = 0;             }             else             {                 ret.data[0].carry = 1;             }         }         else             ret.data[i].carry = 0;         ret.data[i].data = lhs.data[i].data + trhs.data[i].data;         if (i 

Here are links to the full source (github made this easier since there is a lot of it)

回答1:

Your code is very messy to me. I did (long)num classes many times before (floating,fixed,uint,templated,...) so here are some hints:

  1. Try to setup ALU architecture similar to real HW implementation.

    Most algorithms are written for such environment. It will clean and speed up your code. In some cases I use asm for this but if you want to be not CPU dependent you can use this class of mine

    ALU source in C++:

    //--------------------------------------------------------------------------- //--- ALU32 class 1.00 ------------------------------------------------------ //--------------------------------------------------------------------------- #ifndef _ALU32_h #define _ALU32_h //--------------------------------------------------------------------------- class ALU32     { public:     BYTE cy;     ALU32() { cy=0; }     void inc(DWORD &c);                                     //  3.4ns +0.2ns for class call     void dec(DWORD &c);                                     //  3.4ns +0.2ns for class call     void add(DWORD &c,DWORD a,DWORD b);                     //  6.3ns +0.2ns for class call     void sub(DWORD &c,DWORD a,DWORD b);                     //  5.0ns +0.2ns for class call     void adc(DWORD &c,DWORD a,DWORD b);                     //  7.4ns +0.2ns for class call     void sbc(DWORD &c,DWORD a,DWORD b);                     //  5.6ns +0.2ns for class call     void mul(DWORD &ch,DWORD &cl,DWORD a,DWORD b);          // 11.0ns +0.2ns for class call     void div(DWORD &c,DWORD &d,DWORD ah,DWORD al,DWORD b);  // 13.5ns +0.2ns for class call     }; //--------------------------------------------------------------------------- void ALU32::inc(DWORD &c) { if (c==0xFFFFFFFF) cy=1; else cy=0; c++; } void ALU32::dec(DWORD &c) { if (c==0x00000000) cy=1; else cy=0; c--; } //--------------------------------------------------------------------------- void ALU32::add(DWORD &c,DWORD a,DWORD b)     {     c=a+b;     cy=DWORD(((a &1)+(b &1)   )>> 1);     cy=DWORD(((a>>1)+(b>>1)+cy)>>31);     } //--------------------------------------------------------------------------- void ALU32::sub(DWORD &c,DWORD a,DWORD b)     {     c=a-b;     if (a> 1);     cy=DWORD(((a>>1)+(b>>1)+cy)>>31);     } //--------------------------------------------------------------------------- void ALU32::sbc(DWORD &c,DWORD a,DWORD b)     {     c=a-b-cy;     if (cy) { if (a
    • mul and div are still CPU dependent, but they can be easily rewritten to not be...
    • DWORD is 32 bit unsigned int
  2. So now if you want to add two arrays (fixed size N):

    ALU32 alu; DWORD a[N],b[N],c[N]; // a[0] is LSB and a[N-1] is MSB  alu.add(c[0],a[0],b[0]); for (int i=1;i

    it is a good idea to use the biggest base you can to improve speed. If you still need 8 bit ALU this can be also easily rewritten and even simplified due to direct access to carry. You can use 16 or 32 bit variables and extract 9th bit as carry directly from sub-results (looks like you are doing it).

  3. Your problem (copied from comment)

    My bet is that your problem is here:

    if (i

    carry should be applied always but the first time (you do it always but the last time). This also reveals other possibility how is your number stored?

    • data[0] is the LSB or MSB (low/most significant bit/byte...)?

    You have to start adding from lowest digits

    • so either you just applying carry the other way around
    • or you are adding from highest to lowest digits

    but booth are incorrect.

PS. in case you need 32 bit ALU style multiplication without asm in pure C/C++ see:



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!