0

I am trying to write a C (with CoolFlux BSP32) program which takes as input an accumulator and displays its decimal value. For example for an acc with the value in hexadecimal FF C000 0000, I want to print "-1.5".

The fractional value needs to be calculated with an error less than 10^(-9), so I need to use 30 bits from the fractional part of the accumulator.

I have tried to reconstruct the fractional part by using a sequence of numbers equal to 10 ^ 9 / 2 ^ current_index if 1 / 2 ^ current_index can be represented in 30 bits, and (10 ^ 9 / 2 ^ (current_index - 1)) - 1) / 2 if 1 / 2 ^ index can not be represented in 30 bits.

Reproduction of the code:

#include"cf6_chess.h"
#include"CoolFlux_defs.h"
#include<stdio.h>

void printf_acc(acc x)
{
    fix h;
    h = extract_high(x << 1);
    int32 fractionalPart; // Its value is integer (rather than rational but not integer).
    fractionalPart = 0;
    if(h < 0) //Its MSB is 1?
    {
        fractionalPart = 500000000;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 250000000;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 125000000;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 62500000;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 31250000;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 15625000;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 7812500;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 3906250;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 1953125;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 976562;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 488281;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 244140;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 122070;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 61035;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 30517;
    }
    h <<= 1;
    if(h < 0)
    {
        fractionalPart += 15258;
    fix low;
    low = extract_low(x << 1);
    if(low < 1)
    {
        fractionalPart += 7629;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 3814;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 1907;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 953;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 476;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 238;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 119;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 59;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 29;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 14;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 7;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 3;
    }
    low <<= 1;
    if(low < 1)
    {
        fractionalPart += 1;
    }
    int32 integerPart;
    integerPart = (extract_ovf(x) << 1) + (extract_ovf(x << 1) & 1);
    if(fractionalPart == 0)
    {
        printf("%i",integerPart);
        return;
    }
    else
    {
        if(integerPart < 0)
        {
            integerPart += 1;
            fractionalPart = 1000000000 - fractionalPart;
        }
    }
    // Removing the zeroes from fractionalPart is not implemented.
    printf("%i.%i\n",integerPart,fractionalPart);
}

void main()
{
    printf_acc(0.75);
}

The implementation works, but is not optimally. What is a more efficient way to achieve this?

user16217248
  • 3,119
  • 19
  • 19
  • 37
User
  • 1
  • 2
  • 2
    Your description is inadequate. Show code, with a [mre]. – Eric Postpischil Jul 21 '23 at 16:42
  • How does the hex value C0000000 represent -1.5 if there are 29 fractional bits? Is it a 1.31 format and you want to ignore the 2 l.s.b.s of the fractional part? – Ian Abbott Jul 21 '23 at 17:26
  • 1
    If you're taking bits *from the fractional part* of the representation of a fixed- or floating-point number, then does it really make sense to reinterpret those as a number with magnitude greater than 1? Maybe it does, but I'm having trouble understanding the details of what you want to do here. – John Bollinger Jul 21 '23 at 17:48
  • 1
    Please provide enough code so others can better understand or reproduce the problem. – Community Jul 21 '23 at 21:24
  • 1
    Since 2\*\*29 < 10\*\*9, one *cannot* represent values with a relative error of less than 10\*\*(-9) with 29 fractional bits. Would it be correct to assume that instead you are using an **s1.30** fixed-point format, able to represent numbers in [-2,2) ? – njuffa Jul 22 '23 at 05:12
  • 1
    Re “`fractionalPart += 976562;`”: This is just wrong. In this and subsequent lines, you are throwing away fractions. The discarded parts can add up, and the sum can be significantly off. It looks like your `h` is simply a fixed-point representation. In that case, what you want to compute is simply `h`/s, where s is the scaling of the fixed-point format. But s is not clear from your post. The title says 29 bits. The hexadecimal sample “FF C000 0000” has 40 bits. `h = extract_high(x << 1);` followed by `h < 0` suggests maybe 30 bits. You **must** clarify the format. – Eric Postpischil Aug 01 '23 at 00:24
  • 1
    To convert to decimal, you can take `h`, after any integer bits have been removed, and multiply by 10. Then the integer bits will be the first decimal digit. Print them (or save them elsewhere), reset them to zero, and multiply by 10 again. Repeat for as many digits as desired. A problem would be multiply 29 bits by 10 can overflow a 32-bit register. So you might need to split the arithmetic into 16-bit chunks. – Eric Postpischil Aug 01 '23 at 00:29
  • 1
    In any case, if you had clarified the question when asked, you would likely have an answer by now, quite possibly with working code. – Eric Postpischil Aug 01 '23 at 00:30

0 Answers0