Thread: I can't spot my mistake...

  1. #121
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Quote Originally Posted by awsdert View Post
    No it doesn't fully work, I had tracked the overwrite down to a situation where realloc had returned a valid pointer but never actually acquired the needed memory, leaving my code to believe it succeeded and carry on as though it had done so, where I had check the return code
    The likelihood of that is very, very small. realloc() is a very old function, and is very much in use. I would hazard a guess that the reason it now works is that under the covers mmap() allocates memory in full pages.

    I'ld find the error and fix it for you if your GitHub repo actually built:

    Code:
    hamster@hamster-envy:~$ git clone GitHub - awsdert/alu: Library modeled after the Arithmetic Logic Unit built into CPUs
    Cloning into 'alu'...
    remote: Enumerating objects: 71, done.
    remote: Counting objects: 100% (71/71), done.
    remote: Compressing objects: 100% (71/71), done.
    remote: Total 537 (delta 38), reused 33 (delta 0), pack-reused 466
    Receiving objects: 100% (537/537), 178.78 KiB | 407.00 KiB/s, done.
    Resolving deltas: 100% (367/367), done.
    hamster@hamster-envy:~$ cd alu
    hamster@hamster-envy:~/alu$ make build
    #MAKECMDGOALS=build
    cd mak && make -j 1 --no-print-directory -f main.mak build
    PRJ_LIB_NAME=alu
    
    
    Cloning into 'unic'...
    remote: Enumerating objects: 198, done.
    remote: Counting objects: 100% (198/198), done.
    remote: Compressing objects: 100% (161/161), done.
    remote: Total 198 (delta 107), reused 115 (delta 26), pack-reused 0
    Receiving objects: 100% (198/198), 61.33 KiB | 286.00 KiB/s, done.
    Resolving deltas: 100% (107/107), done.
    
    
    Checking 3rd Party libraries are upto date
    cd '../cloned/unic' && git fetch && git pull
    Finished checking
    PRJ_DST_BIN=test_alu.AppImage
    PRJ_DST_LIB=libalu.so
    mkdir ../bin
    mkdir ../lib
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_vec.o -c ../src/alu_vec.c
    In file included from /usr/include/stdio.h:41:0,
                     from ../include/alu.h:11,
                     from ../src/alu_vec.c:1:
    /usr/include/x86_64-linux-gnu/bits/libio.h:466:58: error: expected declaration specifiers or ‘...’ before ‘)’ token
     extern _IO_ssize_t _IO_padn (_IO_FILE *, int, _IO_ssize_t);
                                                              ^
    main.mak:147: recipe for target '../src/alu_vec.o' failed
    make[1]: *** [../src/alu_vec.o] Error 1
    makefile:9: recipe for target 'build' failed
    make: *** [build] Error 2
    Even when I try to hotwire the build process, things are not right, especially in tests/test_alu.c:

    Code:
    hamster@hamster-envy:~/alu/src$ gcc -o alu *.c ../tests/test_alu.c -I ../include -I ../cloned/unic/include/
    ../tests/test_alu.c: In function ‘rng’:
    ../tests/test_alu.c:232:6: warning: implicit declaration of function ‘ror’ [-Wimplicit-function-declaration]
      n = ror( n, X % bitsof(size_t) );
          ^~~
    ../tests/test_alu.c: In function ‘func_wrChar32’:
    ../tests/test_alu.c:519:7: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
       ret = alu_block_expand( dst, dst->taken + 50 );
           ^
    ../tests/test_alu.c: In function ‘reg_print_value’:
    ../tests/test_alu.c:556:35: warning: passing argument 2 of ‘alu_get_reg_node’ makes integer from pointer without a cast [-Wint-conversion]
      int ret = alu_get_reg_node( alu, &tmp, 0 );
                                       ^
    In file included from ../tests/test_alu.c:1:0:
    ../include/alu.h:346:8: note: expected ‘size_t {aka long unsigned int}’ but argument is of type ‘uint_t * {aka unsigned int *}’
     uint_t alu_get_reg_node( alu_t *alu, size_t need );
            ^~~~~~~~~~~~~~~~
    ../tests/test_alu.c:556:12: error: too many arguments to function ‘alu_get_reg_node’
      int ret = alu_get_reg_node( alu, &tmp, 0 );
    ....

  2. #122
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by hamster_nz View Post
    The likelihood of that is very, very small. realloc() is a very old function, and is very much in use. I would hazard a guess that the reason it now works is that under the covers mmap() allocates memory in full pages.

    I'ld find the error and fix it for you if your GitHub repo actually built:

    Code:
    hamster@hamster-envy:~$ git clone GitHub - awsdert/alu: Library modeled after the Arithmetic Logic Unit built into CPUs
    Cloning into 'alu'...
    remote: Enumerating objects: 71, done.
    remote: Counting objects: 100% (71/71), done.
    remote: Compressing objects: 100% (71/71), done.
    remote: Total 537 (delta 38), reused 33 (delta 0), pack-reused 466
    Receiving objects: 100% (537/537), 178.78 KiB | 407.00 KiB/s, done.
    Resolving deltas: 100% (367/367), done.
    hamster@hamster-envy:~$ cd alu
    hamster@hamster-envy:~/alu$ make build
    #MAKECMDGOALS=build
    cd mak && make -j 1 --no-print-directory -f main.mak build
    PRJ_LIB_NAME=alu
    
    
    Cloning into 'unic'...
    remote: Enumerating objects: 198, done.
    remote: Counting objects: 100% (198/198), done.
    remote: Compressing objects: 100% (161/161), done.
    remote: Total 198 (delta 107), reused 115 (delta 26), pack-reused 0
    Receiving objects: 100% (198/198), 61.33 KiB | 286.00 KiB/s, done.
    Resolving deltas: 100% (107/107), done.
    
    
    Checking 3rd Party libraries are upto date
    cd '../cloned/unic' && git fetch && git pull
    Finished checking
    PRJ_DST_BIN=test_alu.AppImage
    PRJ_DST_LIB=libalu.so
    mkdir ../bin
    mkdir ../lib
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_vec.o -c ../src/alu_vec.c
    In file included from /usr/include/stdio.h:41:0,
                     from ../include/alu.h:11,
                     from ../src/alu_vec.c:1:
    /usr/include/x86_64-linux-gnu/bits/libio.h:466:58: error: expected declaration specifiers or ‘...’ before ‘)’ token
     extern _IO_ssize_t _IO_padn (_IO_FILE *, int, _IO_ssize_t);
                                                              ^
    main.mak:147: recipe for target '../src/alu_vec.o' failed
    make[1]: *** [../src/alu_vec.o] Error 1
    makefile:9: recipe for target 'build' failed
    make: *** [build] Error 2
    Even when I try to hotwire the build process, things are not right, especially in tests/test_alu.c:

    Code:
    hamster@hamster-envy:~/alu/src$ gcc -o alu *.c ../tests/test_alu.c -I ../include -I ../cloned/unic/include/
    ../tests/test_alu.c: In function ‘rng’:
    ../tests/test_alu.c:232:6: warning: implicit declaration of function ‘ror’ [-Wimplicit-function-declaration]
      n = ror( n, X % bitsof(size_t) );
          ^~~
    ../tests/test_alu.c: In function ‘func_wrChar32’:
    ../tests/test_alu.c:519:7: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
       ret = alu_block_expand( dst, dst->taken + 50 );
           ^
    ../tests/test_alu.c: In function ‘reg_print_value’:
    ../tests/test_alu.c:556:35: warning: passing argument 2 of ‘alu_get_reg_node’ makes integer from pointer without a cast [-Wint-conversion]
      int ret = alu_get_reg_node( alu, &tmp, 0 );
                                       ^
    In file included from ../tests/test_alu.c:1:0:
    ../include/alu.h:346:8: note: expected ‘size_t {aka long unsigned int}’ but argument is of type ‘uint_t * {aka unsigned int *}’
     uint_t alu_get_reg_node( alu_t *alu, size_t need );
            ^~~~~~~~~~~~~~~~
    ../tests/test_alu.c:556:12: error: too many arguments to function ‘alu_get_reg_node’
      int ret = alu_get_reg_node( alu, &tmp, 0 );
    ....
    I'll take a closer look at your build problem 2mw after work, as for test_alu.c I might abandon that one altogether now that I'm getting the hang of the check library, anyways for now use make check or make rebuild check as I haven't been maintaining test_alu.c whilst I've been setting up the check_alu.c

  3. #123
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by hamster_nz View Post
    The likelihood of that is very, very small. realloc() is a very old function, and is very much in use. I would hazard a guess that the reason it now works is that under the covers mmap() allocates memory in full pages.

    I'ld find the error and fix it for you if your GitHub repo actually built:

    Code:
    hamster@hamster-envy:~$ git clone GitHub - awsdert/alu: Library modeled after the Arithmetic Logic Unit built into CPUs
    Cloning into 'alu'...
    remote: Enumerating objects: 71, done.
    remote: Counting objects: 100% (71/71), done.
    remote: Compressing objects: 100% (71/71), done.
    remote: Total 537 (delta 38), reused 33 (delta 0), pack-reused 466
    Receiving objects: 100% (537/537), 178.78 KiB | 407.00 KiB/s, done.
    Resolving deltas: 100% (367/367), done.
    hamster@hamster-envy:~$ cd alu
    hamster@hamster-envy:~/alu$ make build
    #MAKECMDGOALS=build
    cd mak && make -j 1 --no-print-directory -f main.mak build
    PRJ_LIB_NAME=alu
    
    
    Cloning into 'unic'...
    remote: Enumerating objects: 198, done.
    remote: Counting objects: 100% (198/198), done.
    remote: Compressing objects: 100% (161/161), done.
    remote: Total 198 (delta 107), reused 115 (delta 26), pack-reused 0
    Receiving objects: 100% (198/198), 61.33 KiB | 286.00 KiB/s, done.
    Resolving deltas: 100% (107/107), done.
    
    
    Checking 3rd Party libraries are upto date
    cd '../cloned/unic' && git fetch && git pull
    Finished checking
    PRJ_DST_BIN=test_alu.AppImage
    PRJ_DST_LIB=libalu.so
    mkdir ../bin
    mkdir ../lib
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_vec.o -c ../src/alu_vec.c
    In file included from /usr/include/stdio.h:41:0,
                     from ../include/alu.h:11,
                     from ../src/alu_vec.c:1:
    /usr/include/x86_64-linux-gnu/bits/libio.h:466:58: error: expected declaration specifiers or ‘...’ before ‘)’ token
     extern _IO_ssize_t _IO_padn (_IO_FILE *, int, _IO_ssize_t);
                                                              ^
    main.mak:147: recipe for target '../src/alu_vec.o' failed
    make[1]: *** [../src/alu_vec.o] Error 1
    makefile:9: recipe for target 'build' failed
    make: *** [build] Error 2
    Even when I try to hotwire the build process, things are not right, especially in tests/test_alu.c:

    Code:
    hamster@hamster-envy:~/alu/src$ gcc -o alu *.c ../tests/test_alu.c -I ../include -I ../cloned/unic/include/
    ../tests/test_alu.c: In function ‘rng’:
    ../tests/test_alu.c:232:6: warning: implicit declaration of function ‘ror’ [-Wimplicit-function-declaration]
      n = ror( n, X % bitsof(size_t) );
          ^~~
    ../tests/test_alu.c: In function ‘func_wrChar32’:
    ../tests/test_alu.c:519:7: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
       ret = alu_block_expand( dst, dst->taken + 50 );
           ^
    ../tests/test_alu.c: In function ‘reg_print_value’:
    ../tests/test_alu.c:556:35: warning: passing argument 2 of ‘alu_get_reg_node’ makes integer from pointer without a cast [-Wint-conversion]
      int ret = alu_get_reg_node( alu, &tmp, 0 );
                                       ^
    In file included from ../tests/test_alu.c:1:0:
    ../include/alu.h:346:8: note: expected ‘size_t {aka long unsigned int}’ but argument is of type ‘uint_t * {aka unsigned int *}’
     uint_t alu_get_reg_node( alu_t *alu, size_t need );
            ^~~~~~~~~~~~~~~~
    ../tests/test_alu.c:556:12: error: too many arguments to function ‘alu_get_reg_node’
      int ret = alu_get_reg_node( alu, &tmp, 0 );
    ....
    test_alu.c has been fixed, the build issue was likely just because I hadn't maintained the file, currently building fine for me now
    Code:
    make build
    cd ../ && make --no-print-directory build
    #MAKECMDGOALS=build
    cd mak && make -j 1 --no-print-directory -f main.mak build
    PRJ_LIB_NAME=alu
    Checking 3rd Party libraries are upto date
    cd '../cloned/unic' && git fetch && git pull
    Finished checking
    PRJ_DST_BIN=test_alu.AppImage
    PRJ_DST_LIB=libalu.so
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_bit.o -c ../src/alu_bit.c
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_fpn.o -c ../src/alu_fpn.c
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_int.o -c ../src/alu_int.c
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_main.o -c ../src/alu_main.c
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_math.o -c ../src/alu_math.c
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_mem.o -c ../src/alu_mem.c
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_uint.o -c ../src/alu_uint.c
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_vec.o -c ../src/alu_vec.c
    cc -D NDEBUG -O3  -fPIC -shared  -o ../lib/libalu.so ../src/alu_bit.o ../src/alu_fpn.o ../src/alu_int.o ../src/alu_main.o ../src/alu_math.o ../src/alu_mem.o ../src/alu_uint.o ../src/alu_vec.o -Wl,-rpath,../lib
    cc -D NDEBUG -O3  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../tests/test_alu.o -c ../tests/test_alu.c
    cc -D NDEBUG -O3  -fPIE -L ../lib  -o ../bin/test_alu.AppImage ../tests/test_alu.o -Wl,-rpath,../lib -l alu
    rm ../src/alu_math.o ../tests/test_alu.o ../src/alu_main.o ../src/alu_uint.o ../src/alu_mem.o ../src/alu_int.o ../src/alu_bit.o ../src/alu_vec.o ../src/alu_fpn.o
    Compilation finished successfully.

  4. #124
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    I see two problems in the latest code I was inspecting:

    Your tests need more than 127 registers, but are limited by:

    Code:
    #define ALU_REG_ID_LIMIT SCHAR_MAX
    Confirmed by adding this code in alu_setup_reg:

    Code:
                    want = HIGHEST( want, ALU_REG_ID_NEED );
    >>                if(want > ALU_REG_ID_LIMIT) {
    >>               alu_printf("Limiting registers to %u",ALU_REG_ID_LIMIT);
    >>            }
                    want = LOWEST( want, ALU_REG_ID_LIMIT );
    It appears you need about 510 registers or so to pass your 'check' tests. When you use mmap this is being hidden as you map a full page of memory, which bypass this check and allows for many more registers.

    Also in alu_vec.c I think this check is suspect, and most likely wrong:


    Code:
    >>>                     if ( Nsize == vec->Nsize)
                            {
                                    return vec->block.block;
                            }
    What are you testing there, and why?

    With these issues addressed the output was identical using mmap() or the earlier malloc/realloc() based code in alu_mem.c.

    PS. Build still fails on Ubuntu

    To get it to compile I had to move this header file around in alu.h:

    Code:
    #include <unic/limits.h>
    #include <errno.h>
    #include <uchar.h>
    #include <float.h>
    #include <ctype.h>
    #include <string.h>
    #include <stdio.h>
    #include <unic/stdint.h>
    And then the link process fails with this error:

    Code:
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIE -L ../lib  -o ../bin/check_alu_d.AppImage ../tests/check_alu_d.o -Wl,-rpath,../lib -l alu_d -l check
    /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libcheck.a(check_run.o): undefined reference to symbol 'timer_settime@@GLIBC_2.3.3'
    //lib/x86_64-linux-gnu/librt.so.1: error adding symbols: DSO missing from command line
    The linkage error can be resolved by adding the following libraries required to support 'check': libm libpthread libsubunit librt

    Currently building by running this in ./src:
    Code:
    gcc -o alu *.c ../tests/check_alu.c -I ../include/ -I ../cloned/unic/include/ -l check -l subunit -l rt -l pthread -lm
    Last edited by hamster_nz; 10-04-2020 at 02:41 AM.

  5. #125
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by hamster_nz View Post
    I see two problems in the latest code I was inspecting:

    Your tests need more than 127 registers, but are limited by:

    Code:
    #define ALU_REG_ID_LIMIT SCHAR_MAX
    Confirmed by adding this code in alu_setup_reg:

    Code:
                    want = HIGHEST( want, ALU_REG_ID_NEED );
    >>                if(want > ALU_REG_ID_LIMIT) {
    >>               alu_printf("Limiting registers to %u",ALU_REG_ID_LIMIT);
    >>            }
                    want = LOWEST( want, ALU_REG_ID_LIMIT );
    Ah, so I was indeed wrong, I did think it weird that realloc somehow both succeeded and failed at once, so it was just a relic of old code, now removed


    Quote Originally Posted by hamster_nz View Post
    Also in alu_vec.c I think this check is suspect, and most likely wrong:


    Code:
    >>>                     if ( Nsize == vec->Nsize)
                            {
                                    return vec->block.block;
                            }
    What are you testing there, and why?
    That was... an avoidance of using memmov() unnecessarily, I failed to remember to call alu_block() though, now rectified

    Quote Originally Posted by hamster_nz View Post
    PS. Build still fails on Ubuntu

    To get it to compile I had to move this header file around in alu.h:

    Code:
    #include <unic/limits.h>
    #include <errno.h>
    #include <uchar.h>
    #include <float.h>
    #include <ctype.h>
    #include <string.h>
    #include <stdio.h>
    #include <unic/stdint.h>
    That was a slight error on my part, should've included unic headers after standard headers as it is supposed to prioritise existing definitions before falling back to it's own

    Quote Originally Posted by hamster_nz View Post
    And then the link process fails with this error:

    Code:
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIE -L ../lib  -o ../bin/check_alu_d.AppImage ../tests/check_alu_d.o -Wl,-rpath,../lib -l alu_d -l check
    /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libcheck.a(check_run.o): undefined reference to symbol 'timer_settime@@GLIBC_2.3.3'
    //lib/x86_64-linux-gnu/librt.so.1: error adding symbols: DSO missing from command line
    The linkage error can be resolved by adding the following libraries required to support 'check': libm libpthread libsubunit librt

    Currently building by running this in ./src:
    Code:
    gcc -o alu *.c ../tests/check_alu.c -I ../include/ -I ../cloned/unic/include/ -l check -l subunit -l rt -l pthread -lm
    Are you sure subunit is needed? Doesn't even exist on my system, maybe it's specific to Ubuntu and it's forks? I'll have to investigate that when I have time, not right this second however. If you feel like trying then see if you can figure out why the division receives a divisor of 0, I've got a zoom meeting now so can't look into it myself just yet

    Edit: Forgot to upload my changes, done that now

  6. #126
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Hi! It now builds without any hacks..

    I had a look at the division routine. I know binary division reasonably well, but this was a little too cryptic for me to work out.

    I would expect to see REM getting things subtracted off, but somehow SEG gets things subtracted.

    Humm - maybe some comments would help...

    Code:
            N = alu_reg_data( alu, NUM );
            
            SEG = REM;
            
            n = alu_reg_end_bit( alu, REM );
            SEG.upto = SEG.from = n.bit + 1;
            n = alu_bit( N, NUM.from );
            
            for ( ; alu_reg_cmp( alu, REM, VAL ) >= 0; ++bits )
            {
                SEG.from--;
                if ( alu_reg_cmp( alu, SEG, VAL ) >= 0 )
                {
                    ret = alu_reg_sub( alu, SEG, VAL );
                    
                    if ( ret == ENODATA )
                        break;
                    
                    alu_reg__shl( alu, NUM, TMP, bits );
                    *(n.ptr) |= n.mask;
                    bits = 0;
                }
            }
            
            if ( SEG.from > REM.from )
                alu_reg__shl( alu, NUM, TMP, (SEG.from - REM.from) );

  7. #127
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by hamster_nz View Post
    Hi! It now builds without any hacks..

    I had a look at the division routine. I know binary division reasonably well, but this was a little too cryptic for me to work out.

    I would expect to see REM getting things subtracted off, but somehow SEG gets things subtracted.

    Humm - maybe some comments would help...

    Code:
            N = alu_reg_data( alu, NUM );
            
            SEG = REM;
            
            n = alu_reg_end_bit( alu, REM );
            SEG.upto = SEG.from = n.bit + 1;
            n = alu_bit( N, NUM.from );
            
            for ( ; alu_reg_cmp( alu, REM, VAL ) >= 0; ++bits )
            {
                SEG.from--;
                if ( alu_reg_cmp( alu, SEG, VAL ) >= 0 )
                {
                    ret = alu_reg_sub( alu, SEG, VAL );
                    
                    if ( ret == ENODATA )
                        break;
                    
                    alu_reg__shl( alu, NUM, TMP, bits );
                    *(n.ptr) |= n.mask;
                    bits = 0;
                }
            }
            
            if ( SEG.from > REM.from )
                alu_reg__shl( alu, NUM, TMP, (SEG.from - REM.from) );
    You see how I set SEG to REM before the loop? That's because I'm defaulting the register information such as which node to REM's, I then override the bits of the node it is referring to to the bit just after the final bit set, here's a clearer example
    Let's say REM is '00110010' and VAL is '00000010', SEG being set to REM's information at first will cause SEG to refer to the entirety of '00110010', overriding upto and from straight after to the bit after the final bit will make it refer to the 2nd 0 from the end, now because from is also set to that bit what SEG can actually reference is an empty value '', however we must start like that for us to then decrement the from parameter at the start of each loop thereby make SEG reference the correct bits, in this case VAL will only be less than or equal to SEG once it is decremented twice creating the comparison of '11' verses '00000010' or in decimal '3' vs '2', the original number being divided is 50 so this would create the decimal 2 of decimal 25 (the correct result of this division), the next value SEG would refer to is '010' as via SEG we already changed REM to '00010010' just as in decimal we would change the 50 to 10 which leads to 10 divided by 2 equaling 5, with SEG we would have 2 more divisions occur as we are in binary shifting along the bits as we go (or in this case once we get to the next efficient opportunity), each time because the node SEG refers to is the same as REM the result is the same type of division as we would do decimal division with a pen and paper (unless you're doing it the slow way)

  8. #128
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Quote Originally Posted by awsdert View Post
    You see how I set SEG to REM before the loop? That's because I'm defaulting the register information such as which node to REM's, I then override the bits of the node it is referring to to the bit just after the final bit set, here's a clearer example
    Let's say REM is '00110010' and VAL is '00000010', SEG being set to REM's information at first will cause SEG to refer to the entirety of '00110010', overriding upto and from straight after to the bit after the final bit will make it refer to the 2nd 0 from the end, now because from is also set to that bit what SEG can actually reference is an empty value '', however we must start like that for us to then decrement the from parameter at the start of each loop thereby make SEG reference the correct bits, in this case VAL will only be less than or equal to SEG once it is decremented twice creating the comparison of '11' verses '00000010' or in decimal '3' vs '2', the original number being divided is 50 so this would create the decimal 2 of decimal 25 (the correct result of this division), the next value SEG would refer to is '010' as via SEG we already changed REM to '00010010' just as in decimal we would change the 50 to 10 which leads to 10 divided by 2 equaling 5, with SEG we would have 2 more divisions occur as we are in binary shifting along the bits as we go (or in this case once we get to the next efficient opportunity), each time because the node SEG refers to is the same as REM the result is the same type of division as we would do decimal division with a pen and paper (unless you're doing it the slow way)
    Oh, I see - didn't see that SEG and REM were looking at the same data. Makes sense.

    I was a little bit perplexed why you were making one or two calls to alu_reg_cmp(), but now see the first one is just saying keep going until the remainder is less than the divisor. It allows you to bail out of the loop early, but I wonder how often enough of the low bits of the result will be zero to make it worthwhile.

    Also, wouldn't it be more convenient to just set the absolute bit in NUM when you do the subtraction, rather than what appears to be shifting bits through the register as you loop?
    Last edited by hamster_nz; 10-06-2020 at 05:22 AM.

  9. #129
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    I fixed the division problem, turned out the issue was split in 2 parts, 1st I noticed that alu_reg_sub() incorrectly reported ENODATA when VAL happened to have no ones aligned with a short NUM, this problem exists in alu_reg_add() also so I will be fixing that in a moment before uploading, the 2nd part of the issue was that I had mishandled a small bit of data in alu_reg_cmp() which resulted in incorrect results, fixed that and all my current tests in check_alu.c passed now, I had to remove the $(F_l) subunit from the flags given to a check build however because it would not build with it there, hamster_nz if you could tell me what system you're on I'll research a way to check for that in the dst_cc.mak and adapt to it so you no longer have to edit the flags

  10. #130
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by hamster_nz View Post
    Oh, I see - didn't see that SEG and REM were looking at the same data. Makes sense.

    I was a little bit perplexed why you were making one or two calls to alu_reg_cmp(), but now see the first one is just saying keep going until the remainder is less than the divisor. It allows you to bail out of the loop early, but I wonder how often enough of the low bits of the result will be zero to make it worthwhile.
    Not sure but for now it reflects the way we do it in decimal on pen and paper, just a little more complex due to the fact pc analysis and human analysis thought does not work the same way

    Quote Originally Posted by hamster_nz View Post
    Also, wouldn't it be more convenient to just set the absolute bit in NUM when you do the subtraction, rather than what appears to be shifting bits through the register as you loop?
    Maybe, however I was first aiming to have it look similar to human division so I could be clear I'm going the right direction with the division, enhancements can come later after all the requirements of a software based ALU to process integer and floating math are in place because that can be marked as stable then (ie. ready for every random John/Jane Doe to download and use)

  11. #131
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Had to reinstall my system due to f***ing up sudo permissions, started using cppcheck and learned something new about C89, I was under the false impression that all variables had to be declared at the start of the function, corrected everything that cppcheck reported, tried finishing off the part of code that forces exponents to match, compiles fine but when running alu_check.c code I ended up with this:
    Code:
    make check
    cd ../ && make --no-print-directory check
    #MAKECMDGOALS=check
    cd mak && make -j 1 --no-print-directory -f main.mak check
    PRJ_LIB_NAME=alu_d
    Checking 3rd Party libraries are upto date
    cd '../cloned/unic' && git fetch && git pull
    Finished checking
    PRJ_DST_BIN=check_alu_d.AppImage
    PRJ_DST_LIB=libalu_d.so
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_bit_d.o -c ../src/alu_bit.c
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_fpn_d.o -c ../src/alu_fpn.c
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_int_d.o -c ../src/alu_int.c
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_main_d.o -c ../src/alu_main.c
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_math_d.o -c ../src/alu_math.c
    ../src/alu_math.c: In function ‘alu_reg_add’:
    ../src/alu_math.c:860:49: warning: variable ‘TMP’ set but not used [-Wunused-but-set-variable]
      860 |   alu_reg_t NCPY, VCPY, NEXP, NMAN, VEXP, VMAN, TMP;
          |                                                 ^~~
    ../src/alu_math.c:860:43: warning: variable ‘VMAN’ set but not used [-Wunused-but-set-variable]
      860 |   alu_reg_t NCPY, VCPY, NEXP, NMAN, VEXP, VMAN, TMP;
          |                                           ^~~~
    ../src/alu_math.c:860:31: warning: variable ‘NMAN’ set but not used [-Wunused-but-set-variable]
      860 |   alu_reg_t NCPY, VCPY, NEXP, NMAN, VEXP, VMAN, TMP;
          |                               ^~~~
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_mem_d.o -c ../src/alu_mem.c
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_uint_d.o -c ../src/alu_uint.c
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../src/alu_vec_d.o -c ../src/alu_vec.c
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -shared  -o ../lib/libalu_d.so ../src/alu_bit_d.o ../src/alu_fpn_d.o ../src/alu_int_d.o ../src/alu_main_d.o ../src/alu_math_d.o ../src/alu_mem_d.o ../src/alu_uint_d.o ../src/alu_vec_d.o -Wl,-rpath,../lib
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIC -Wall -Wextra -pedantic -I ../cloned/unic/include -I ../include -D UNIC_FALLBACK  -o ../tests/check_alu_d.o -c ../tests/check_alu.c
    In file included from ../tests/check_alu.c:181:
    ../tests/check_alu.c:490:13: warning: ‘test_alu_reg2str’ defined but not used [-Wunused-variable]
      490 | START_TEST( test_alu_reg2str )
          |             ^~~~~~~~~~~~~~~~
    ../tests/check_alu.c:356:13: warning: ‘test_alu_op3’ defined but not used [-Wunused-variable]
      356 | START_TEST( test_alu_op3 )
          |             ^~~~~~~~~~~~
    cc -ggdb -D _DEBUG -O0 -fsanitize=address  -fPIE -L ../lib  -o ../bin/check_alu_d.AppImage ../tests/check_alu_d.o -Wl,-rpath,../lib -l alu_d -l check  -l rt -l pthread -l m
    ../bin/check_alu_d.AppImage
    ../tests/check_alu.c:863: main() 'Running unit tests under 'check' test suite'
    Running suite(s): ALU
    ../src/alu_math.c:1174: alu_reg__shl() 'alu' was null
    ...
    ../src/alu_math.c:1174: alu_reg__shl() 'alu' was null
    100%: Checks: 1221, Failures: 0, Errors: 0
    ../src/alu_math.c:1174: alu_reg__shl() 'alu' was null
    ...
    ../src/alu_math.c:1174: alu_reg__shl() 'alu' was null
    rm ../src/alu_int_d.o ../src/alu_math_d.o ../tests/check_alu_d.o ../src/alu_main_d.o ../src/alu_uint_d.o ../src/alu_fpn_d.o ../src/alu_bit_d.o ../src/alu_mem_d.o ../src/alu_vec_d.o
    ../src/alu_math.c:1174: alu_reg__shl() 'alu' was null
    ...
    ../src/alu_math.c:1174: alu_reg__shl() 'alu' was null
    Compilation finished successfully.
    The ... is in place of a LOT of the same message, tried looking for the issue in code but couldn't find it, was gonna debug it but gede wouldn't build/install due to missing source package at AUR, got overtime to go to in few minutes so was hoping someone could debug this for me to find why I get a NULL and just post their findings for me to work from when I get back or 2mw morning (also got overtime 2mw hence morning)

  12. #132
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Found the issue, I forgot to add a return 0; at the end of the successful scope, did that and the error went away, btw it turned out the reason gede wouldn't compile was because the dev changed domain but didn't update the scripts

  13. #133
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    *sigh* Another problem I'm not seeing the cause of, not getting the right value out of my exponent and mantissa when I do addition, here's the code snippet (from alu_math.c):
    Code:
    int_t alu_match_exponents
    (
    	alu_t *alu
    	, uint_t num
    	, uint_t val
    )
    {
    	if ( alu )
    	{
    		int_t ret;
    		alu_reg_t NUM, VAL, NEXP, VEXP, NMAN, VMAN;
    		size_t nexp;
    				
    		alu_reg_init_floating( alu, NUM, num );
    		alu_reg_init_floating( alu, VAL, val );
    		
    		NUM.upto = alu_Nbits(alu);
    		VAL.upto = alu_Nbits(alu);
    				
    		alu_reg_init_mantissa( NUM, NMAN );
    		alu_reg_init_exponent( NUM, NEXP );
    		
    		alu_reg_init_mantissa( VAL, VMAN );
    		alu_reg_init_exponent( VAL, VEXP );
    		
    		ret = alu_reg_get_raw( alu, NEXP, &nexp, sizeof(size_t) );
    		
    		if ( ret == 0 )
    		{
    			size_t vexp, diff;
    			
    			(void)alu_reg_get_raw( alu, VEXP, &vexp, sizeof(size_t) );
    				
    			diff = SET2IF( nexp > vexp, nexp - vexp, vexp - nexp );
    			
    			if ( diff >= NMAN.upto )
    			{
    				if ( nexp > vexp )
    				{
    					alu_reg_clr( alu, VMAN );
    					alu_reg_int2int( alu, VEXP, NEXP );
    				}
    				else
    				{
    					alu_reg_clr( alu, NMAN );
    					alu_reg_int2int( alu, NEXP, VEXP );
    				}
    				
    				/* We'll use this to indicate truncation, should be impossible
    				 * in this case given we are taking more space than the
    				 * developer would normally take if they use the API as
    				 * intended, this at least covers the being abused scenario */
    				return ERANGE;
    			}
    			
    			if ( diff )
    			{
    				/* We don't check for success here because prior functions we
    				 * called already got & released the register we're about to
    				 * recieve */
    				uint_t tmp = alu_get_reg_node( alu, 0 );
    				alu_reg_t TMP;
    				alu_bit_t n;
    				
    				alu_reg_init_unsigned( alu, TMP, tmp );
    				
    				if ( nexp > vexp )
    				{
    					n = alu_bit( (void*)alu_reg_data( alu, VMAN ), 0 );
    					for ( ; ret == 0 && n.bit < diff; alu_bit_inc(&n) )
    					{
    						ret = SET1IF( *(n.ptr) & n.mask, ENOBUFS );
    					}
    					
    					alu_reg__shr( alu, VMAN, TMP, diff );
    				}
    				else
    				{
    					n = alu_bit( (void*)alu_reg_data( alu, NMAN ), 0 );
    					for ( ; ret == 0 && n.bit < diff; alu_bit_inc(&n) )
    					{
    						ret = SET1IF( *(n.ptr) & n.mask, ERANGE );
    					}
    					
    					alu_reg__shr( alu, VMAN, TMP, diff );
    				}
    				
    				alu_rem_reg_node( alu, &tmp );
    				
    				if ( ret )
    					alu_error(ret);
    			}
    			
    			return ret;
    		}
    		
    		alu_error(ret);
    		return ret;
    	}
    	
    	return alu_err_null_ptr("alu");
    }
    
    int_t alu_reg_addition(
    	alu_t *alu
    	, alu_reg_t NUM
    	, alu_reg_t VAL
    	, uint_t cpy
    	, uint_t tmp
    )
    {	
    	if ( alu )
    	{
    		int ret;
    		bool carry = false, changed = false;
    		alu_bit_t n, v;
    		size_t pos;
    		void *part;
    		alu_reg_t CPY, CEXP, CMAN, TEXP, TMAN, TMP;
    		
    		NUM.node %= alu_used( alu );
    		VAL.node %= alu_used( alu );
    		
    		ret = SET1IF( !NUM.node || !VAL.node, EINVAL );
    			
    		if ( ret )
    		{
    			alu_error( ret );
    			
    			if ( !NUM.node ) alu_puts( "NUM.node was 0!" );
    			
    			if ( !VAL.node ) alu_puts( "VAL.node was 0!" );
    			
    			return ret;
    		}
    		
    		if ( alu_reg_floating( VAL ) )
    		{				
    			alu_reg_init_floating( alu, TMP, tmp );
    			
    			TMP.upto = alu_Nbits(alu);
    			
    			/* VAL is supposed to be unchanged so use VCPY instead */
    			ret = alu_reg_mov( alu, TMP, VAL );
    			
    			if ( ret == 0 )
    			{	
    				alu_reg_init_floating( alu, CPY, cpy );
    				
    				CPY.upto = alu_Nbits(alu);
    				
    				/* Need NUM to be unchanged so can restore details later,
    				* having both floats the same size also makes math easier,
    				* also no chance of failure here as the previous move
    				* succeeded in getting the same temporary registers this
    				* one will be looking for */
    				(void)alu_reg_mov( alu, CPY, NUM );
    				
    				ret = alu_match_exponents( alu, cpy, tmp );
    				
    				if ( ret == 0 )
    				{
    					alu_reg_init_exponent( CPY, CEXP );
    					alu_reg_init_exponent( TMP, TEXP );
    					
    					alu_reg_init_mantissa( CPY, CMAN );
    					alu_reg_init_mantissa( TMP, TMAN );
    					
    					ret = alu_reg_add( alu, CMAN, TMAN );
    					
    					/* No chance of failure here either */
    					(void)alu_reg_mov( alu, NUM, CPY );
    					
    					return ret;
    				}
    			}
    			
    			alu_error(ret);
    			return ret;
    		}
    And here's a few results (top NUM is what I got, bottom num is correct result copied into NUM):
    Code:
    Running suite(s): ALU
    ../src/alu_math.c:1004: alu_reg_addition() Error 0x00000022 34 'Numerical result out of range'
    ../src/alu_math.c:1103: alu_reg_add() Error 0x00000022 34 'Numerical result out of range'
    ../tests/check_alu.c:967: test_alu_reg_add_floating_fn() _num = 0, _val = 1, (EXP.upto = 63) - (EXP.from = 52) = 11, (MAN.upto = 52) - (MAN.from = 0) = 52
    ../tests/check_alu.c:978: test_alu_reg_add_floating_fn() NUM = 0000000000000000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:980: test_alu_reg_add_floating_fn() NUM = 0011111111110000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:967: test_alu_reg_add_floating_fn() _num = 1, _val = 1, (EXP.upto = 63) - (EXP.from = 52) = 11, (MAN.upto = 52) - (MAN.from = 0) = 52
    ../tests/check_alu.c:978: test_alu_reg_add_floating_fn() NUM = 0011111111110000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:980: test_alu_reg_add_floating_fn() NUM = 0100000000000000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:967: test_alu_reg_add_floating_fn() _num = 2, _val = 1, (EXP.upto = 63) - (EXP.from = 52) = 11, (MAN.upto = 52) - (MAN.from = 0) = 52
    ../tests/check_alu.c:978: test_alu_reg_add_floating_fn() NUM = 0100000000000000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:980: test_alu_reg_add_floating_fn() NUM = 0100000000001000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:967: test_alu_reg_add_floating_fn() _num = 3, _val = 1, (EXP.upto = 63) - (EXP.from = 52) = 11, (MAN.upto = 52) - (MAN.from = 0) = 52
    ../tests/check_alu.c:978: test_alu_reg_add_floating_fn() NUM = 0100000000000000000000010000000000000000000000000000000000000000
    ../tests/check_alu.c:980: test_alu_reg_add_floating_fn() NUM = 0100000000010000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:967: test_alu_reg_add_floating_fn() _num = 4, _val = 1, (EXP.upto = 63) - (EXP.from = 52) = 11, (MAN.upto = 52) - (MAN.from = 0) = 52
    ../tests/check_alu.c:978: test_alu_reg_add_floating_fn() NUM = 0100000000010000000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:980: test_alu_reg_add_floating_fn() NUM = 0100000000010100000000000000000000000000000000000000000000000000
    ../tests/check_alu.c:967: test_alu_reg_add_floating_fn() _num = 5, _val = 1, (EXP.upto = 63) - (EXP.from = 52) = 11, (MAN.upto = 52) - (MAN.from = 0) = 52
    ../tests/check_alu.c:978: test_alu_reg_add_floating_fn() NUM = 0100000000010000000000001000000000000000000000000000000000000000
    ../tests/check_alu.c:980: test_alu_reg_add_floating_fn() NUM = 0100000000011000000000000000000000000000000000000000000000000000
    Here's the video that I'm using to understand FPN addition: Binary 7 – Floating Point Binary Addition - YouTube
    And here's the one I used to understand how to set the exponent and mantissa: Floating Point Numbers - YouTube
    Oh if anyone figures out how to stop the 3 extra runs of building/running when I run "make check run" I would greatly appreciate you posting it.

    I'm gonna take a break, maybe fresh will help me later if noone tries or manages to figure out the cause

  14. #134
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Still failing to manage the addition correctly, made some changes however so should be easier to understand the code as a result:
    Code:
    int_t alu_match_exponents_and_normalise
    (
    	alu_t *alu
    	, uint_t num
    	, uint_t val
    	, uint_t tmp
    )
    {
    	if ( alu )
    	{
    		int_t ret;
    		alu_reg_t NUM, VAL, NEXP, VEXP, NMAN, VMAN, TMP;
    		size_t nexp;
    			
    		alu_reg_init_floating( alu, NUM, num );
    		alu_reg_init_floating( alu, VAL, val );
    		alu_reg_init_unsigned( alu, TMP, tmp );
    		
    		NUM.upto = alu_Nbits(alu);
    		VAL.upto = alu_Nbits(alu);
    				
    		alu_reg_init_mantissa( NUM, NMAN );
    		alu_reg_init_exponent( NUM, NEXP );
    		
    		alu_reg_init_mantissa( VAL, VMAN );
    		alu_reg_init_exponent( VAL, VEXP );
    		
    		ret = alu_reg_get_raw( alu, NEXP, &nexp, sizeof(size_t) );
    		
    		if ( ret == 0 )
    		{
    			size_t vexp, diff;
    			bool truncated = false;
    			
    			(void)alu_reg_get_raw( alu, VEXP, &vexp, sizeof(ssize_t) );
    			
    			alu->block.fault = 0;
    			
    			if ( nexp > vexp )
    			{
    				diff = nexp - vexp;
    				
    				/* Match exponent and align mantissa */
    				alu_reg_int2int( alu, VEXP, NEXP );
    				alu_reg__shr( alu, VMAN, TMP, diff );
    				truncated = (alu_errno(alu) == ERANGE);
    				
    				/* Insert assumed bit back into position */
    				if ( diff < VMAN.upto )
    				{
    					void *V = alu_reg_data( alu, VAL );
    					alu_bit_t v = alu_bit( V, VMAN.upto - diff );
    					*(v.ptr) |= v.mask;
    				
    					/* Normalise */
    					diff = VMAN.upto - v.bit;
    					
    					alu->block.fault = 0;
    					alu_reg__shr( alu, NMAN, TMP, diff );
    					truncated = (truncated || alu_errno(alu) == ERANGE);
    					alu_reg__shr( alu, VMAN, TMP, diff );
    					vexp = nexp + diff;
    					alu_reg_set_raw( alu, VEXP, &vexp, sizeof(size_t), 0 );
    				}
    			}
    			else if ( vexp > nexp )
    			{
    				diff = vexp - nexp;
    				
    				alu_reg_int2int( alu, NEXP, VEXP );
    				alu_reg__shr( alu, NMAN, TMP, diff );
    				truncated = (alu_errno(alu) == ERANGE);
    				
    				/* Insert assumed bit back into position */
    				if ( diff < NMAN.upto )
    				{
    					void *N = alu_reg_data( alu, NUM );
    					alu_bit_t n = alu_bit( N, NMAN.upto - diff );
    					*(n.ptr) |= n.mask;
    				
    					/* Normalise */
    					diff = NMAN.upto - n.bit;
    					
    					alu_reg__shr( alu, NMAN, TMP, diff );
    					alu->block.fault = 0;
    					alu_reg__shr( alu, VMAN, TMP, diff );
    					truncated = (truncated || alu_errno(alu) == ERANGE);
    					nexp = vexp + diff;
    					alu_reg_set_raw( alu, NEXP, &nexp, sizeof(size_t), 0 );
    				}
    			}
    			
    			
    			alu->block.fault = SET1IF(truncated,ERANGE);
    			
    			return 0;
    		}
    		
    		alu_error(ret);
    		return ret;
    	}
    	
    	return alu_err_null_ptr("alu");
    }
    
    int_t alu_reg_addition(
    	alu_t *alu
    	, alu_reg_t NUM
    	, alu_reg_t VAL
    	, uint_t cpy
    	, uint_t tmp
    )
    {	
    	if ( alu )
    	{
    		int ret;
    		bool carry = false, changed = false;
    		alu_bit_t n, v;
    		size_t pos;
    		void *part;
    		alu_reg_t CPY, CEXP, CMAN, TEXP, TMAN, TMP;
    		
    		NUM.node %= alu_used( alu );
    		VAL.node %= alu_used( alu );
    		
    		ret = SET1IF( !NUM.node || !VAL.node, EINVAL );
    			
    		if ( ret )
    		{
    			alu_error( ret );
    			
    			if ( !NUM.node ) alu_puts( "NUM.node was 0!" );
    			
    			if ( !VAL.node ) alu_puts( "VAL.node was 0!" );
    			
    			return ret;
    		}
    		
    		if ( alu_reg_floating( VAL ) )
    		{
    			uint_t temp = alu_get_reg_node( alu, 0 );
    			
    			if ( temp )
    			{
    				alu_reg_init_floating( alu, TMP, tmp );
    				
    				TMP.upto = alu_Nbits(alu);
    				
    				/* VAL is supposed to be unchanged so use VCPY instead */
    				ret = alu_reg_mov( alu, TMP, VAL );
    				
    				if ( ret == 0 )
    				{	
    					alu_reg_init_floating( alu, CPY, cpy );
    					
    					CPY.upto = alu_Nbits(alu);
    					
    					/* Need NUM to be unchanged so can restore details later,
    					* having both floats the same size also makes math easier,
    					* also no chance of failure here as the previous move
    					* succeeded in getting the same temporary registers this
    					* one will be looking for */
    					(void)alu_reg_mov( alu, CPY, NUM );
    					
    					ret = alu_match_exponents_and_normalise( alu, cpy, tmp, temp );
    					
    					if ( ret == 0 )
    					{
    						bool truncated = (alu_errno(alu) == ERANGE);
    						
    						alu_reg_init_exponent( CPY, CEXP );
    						alu_reg_init_exponent( TMP, TEXP );
    						
    						alu_reg_init_mantissa( CPY, CMAN );
    						alu_reg_init_mantissa( TMP, TMAN );
    						
    						ret = alu_reg_add( alu, CMAN, TMAN );
    						
    						if ( ret == EOVERFLOW )
    						{
    							ret = alu_reg_inc( alu, CEXP );
    						}
    						
    						/* No chance of failure here either */
    						(void)alu_reg_mov( alu, NUM, CPY );
    						
    						alu_rem_reg_node( alu, &temp );
    						
    						return SET2IF( truncated, ERANGE, ret );
    					}
    				}
    				
    				alu_rem_reg_node( alu, &temp );
    			}
    			
    			alu_error(ret);
    			return ret;
    		}
    Here's a link to the uploaded compile log (forums refused to understand it was a text file)
    alu_check.log - Google Drive

  15. #135
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Made some changes, fixed alu_reg_flt2flt() which was actually buggy (caught it while trying and still failing to fix FPN addition), mades an improvment to alu_print_reg() to add spaces between the different bit sections making it easier to understand what bits are part of what section (did that because I was struggling to see if it was just the mantissa that was the issue, which I just now realise I still forgot to check) created a new compile log with all the changes which in case google created a different link is here: alu_check.log - Google Drive

    I re-watched the vid and realised I made a misunderstanding so ripped out the normalization code from matching the exponents, also some changes to the code calling it so here's both:
    Code:
    int_t alu_match_exponents
    (
    	alu_t *alu
    	, uint_t num
    	, uint_t val
    	, uint_t tmp
    )
    {
    	if ( alu )
    	{
    		int_t ret;
    		alu_reg_t NUM, VAL, NEXP, VEXP, NMAN, VMAN, TMP;
    		size_t nexp;
    			
    		alu_reg_init_floating( alu, NUM, num );
    		alu_reg_init_floating( alu, VAL, val );
    		alu_reg_init_unsigned( alu, TMP, tmp );
    		
    		NUM.upto = alu_Nbits(alu);
    		VAL.upto = alu_Nbits(alu);
    				
    		alu_reg_init_mantissa( NUM, NMAN );
    		alu_reg_init_exponent( NUM, NEXP );
    		
    		alu_reg_init_mantissa( VAL, VMAN );
    		alu_reg_init_exponent( VAL, VEXP );
    		
    		ret = alu_reg_get_raw( alu, NEXP, &nexp, sizeof(size_t) );
    		
    		if ( ret == 0 )
    		{
    			size_t vexp, diff;
    			bool truncated = false;
    			
    			(void)alu_reg_get_raw( alu, VEXP, &vexp, sizeof(ssize_t) );
    			
    			alu->block.fault = 0;
    			
    			if ( nexp > vexp )
    			{
    				diff = nexp - vexp;
    				
    				/* Match exponent and align mantissa */
    				alu_reg_int2int( alu, VEXP, NEXP );
    				alu_reg__shr( alu, VMAN, TMP, diff );
    				truncated = (alu_errno(alu) == ERANGE);
    				
    				/* Insert assumed bit back into position */
    				if ( diff < VMAN.upto )
    				{
    					void *V = alu_reg_data( alu, VAL );
    					alu_bit_t v = alu_bit( V, VMAN.upto - diff );
    					*(v.ptr) |= v.mask;
    				
    					/* Normalise */
    					diff = VMAN.upto - v.bit;
    				}
    			}
    			else if ( vexp > nexp )
    			{
    				diff = vexp - nexp;
    				
    				alu_reg_int2int( alu, NEXP, VEXP );
    				alu_reg__shr( alu, NMAN, TMP, diff );
    				truncated = (alu_errno(alu) == ERANGE);
    				
    				/* Insert assumed bit back into position */
    				if ( diff < NMAN.upto )
    				{
    					void *N = alu_reg_data( alu, NUM );
    					alu_bit_t n = alu_bit( N, NMAN.upto - diff );
    					*(n.ptr) |= n.mask;
    				}
    			}
    			
    			alu->block.fault = IFTRUE(truncated,ERANGE);
    			
    			return 0;
    		}
    		
    		alu_error(ret);
    		return ret;
    	}
    	
    	return alu_err_null_ptr("alu");
    }
    
    int_t alu_reg_addition(
    	alu_t *alu
    	, alu_reg_t NUM
    	, alu_reg_t VAL
    	, uint_t cpy
    	, uint_t tmp
    )
    {	
    	if ( alu )
    	{
    		int ret;
    		bool carry = false, changed = false;
    		alu_bit_t n, v;
    		size_t pos;
    		void *part;
    		alu_reg_t CPY, CEXP, CMAN, TEXP, TMAN, TMP;
    		
    		NUM.node %= alu_used( alu );
    		VAL.node %= alu_used( alu );
    		
    		ret = IFTRUE( !NUM.node || !VAL.node, EINVAL );
    			
    		if ( ret )
    		{
    			alu_error( ret );
    			
    			if ( !NUM.node ) alu_puts( "NUM.node was 0!" );
    			
    			if ( !VAL.node ) alu_puts( "VAL.node was 0!" );
    			
    			return ret;
    		}
    		
    		if ( alu_reg_floating( VAL ) )
    		{
    			alu_reg_init_floating( alu, TMP, tmp );
    			
    			TMP.upto = alu_Nbits(alu);
    			
    			/* VAL is supposed to be unchanged so use VCPY instead */
    			ret = alu_reg_mov( alu, TMP, VAL );
    			
    			if ( ret == 0 )
    			{	
    				alu_reg_init_floating( alu, CPY, cpy );
    				
    				CPY.upto = alu_Nbits(alu);
    				
    				/* Need NUM to be unchanged so can restore details later,
    				* having both floats the same size also makes math easier,
    				* also no chance of failure here as the previous move
    				* succeeded in getting the same temporary registers this
    				* one will be looking for */
    				(void)alu_reg_mov( alu, CPY, NUM );
    				
    				uint_t temp = alu_get_reg_node( alu, 0 );
    		
    				if ( temp )
    				{					
    					ret = alu_match_exponents( alu, cpy, tmp, temp );
    					
    					alu_rem_reg_node( alu, &temp );
    					
    					if ( ret == 0 )
    					{
    						bool truncated = (alu_errno(alu) == ERANGE);
    						uint_t nodes[2];
    						
    						ret = alu_get_reg_nodes( alu, nodes, 2, 0 );
    						
    						if ( ret == 0 )
    						{
    							alu_reg_t _CMAN, _TMAN;
    							size_t bias, cexp;
    							
    							alu_reg_init_unsigned( alu, _CMAN, nodes[0] );
    							alu_reg_init_unsigned( alu, _TMAN, nodes[1] );
    							
    							alu_reg_init_exponent( CPY, CEXP );
    							alu_reg_init_exponent( TMP, TEXP );
    							
    							alu_reg_init_mantissa( CPY, CMAN );
    							alu_reg_init_mantissa( TMP, TMAN );
    							
    							alu_reg_int2int( alu, _CMAN, CMAN );
    							alu_reg_int2int( alu, _TMAN, TMAN );
    							
    							ret = alu_reg_add( alu, _CMAN, _TMAN );
    							
    							switch ( ret )
    							{
    							case 0: case EOVERFLOW: case ENODATA: break;
    							default:
    								alu_rem_reg_nodes( alu, nodes, 2 );
    								alu_error(ret);
    								return ret;
    							}
    							
    							n = alu_reg_end_bit( alu, _CMAN );
    							(void)alu_reg_get_exponent( alu, CPY, &cexp );
    							
    							bias = alu_reg_get_exponent_bias( CPY );
    							cexp -= bias;
    							
    							ret = alu_reg_set_raw( alu, CEXP, &(n.bit), sizeof(size_t), 0 );
    							
    							/* No chance of failure at this point */
    							(void)alu_reg_mov( alu, NUM, CPY );
    							
    							alu_rem_reg_nodes( alu, nodes, 2 );
    							return EITHER( truncated, ERANGE, ret );
    						}
    					}
    				}
    				else
    				{
    					ret = alu_errno(alu);
    				}
    			}
    			
    			alu_error(ret);
    			return ret;
    		}
    Gonna grab something to eat, hopefully someone manages to spot where I went wrong, as a reminder the vids I'm using to understand FPN addition are 2 posts prior to this one

    Edit: Just remembered that I thought of more appropriate names for the SET1IF and SET2IF macros, they've now been renamed to IFTRUE and EITHER respectively, they're in alu.h if you need to refresh your memory on what they do

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. can anyone help to spot mistake in the code
    By chess_queen in forum C Programming
    Replies: 1
    Last Post: 10-21-2012, 10:37 AM
  2. Can you spot my mistake?
    By Brewer in forum C Programming
    Replies: 13
    Last Post: 11-12-2006, 12:50 PM
  3. going to a certain spot in a file...
    By agerealm in forum C++ Programming
    Replies: 3
    Last Post: 05-17-2002, 02:31 AM

Tags for this Thread