C语言 如何正确打印2.30定点变量

jv2fixgn  于 2023-08-03  发布在  其他
关注(0)|答案(2)|浏览(109)

我在用皮质M3获取离散傅里叶变换我使用CMSIS DSP函数arm_cmplx_mag_q31计算幅度。文档说它以2.30的格式返回结果(我假设整数是2位,小数部分是30位;没有符号位,因为幅度不能为负)。
我试图将结果输出给用户,但我发现很难打印出正确的值。
我已经尝试过使用typedef定义一个新的联合体,我可以像这样存储整数和小数部分

/* 2.30 union*/
typedef union {
  uint32_t full;
  struct {
    uint32_t fpart:30;
    uint8_t  ipart:2;
  } parts;
} fixed2_30_t;

字符串
然后将2.30星等结果存储到fixed2_30_t变量中,并尝试打印其部分

fixed2_30_t   result;
result = magnitude;

sprintf(msg, "final results %0d.%010u", 
        result.parts.ipart, result.parts.fpart / 1073741824);


我将小数部分除以2^30以将其缩放回小数,但我没有获得合理的结果,并且我不完全确定我的零填充是否正确。
打印的正确方法是什么?如何确定要使用的零填充?
谢谢你,谢谢

yc0p9oo0

yc0p9oo01#

如何正确打印2.30定点变量
若要打印到.后面的10位小数,请将分数缩放1010,然后除以232。
使用unsigned long long数学来确保概率。请注意,下面的乘积(最大值为.fpart)是一个64位正值。

sprintf(msg, "final results %0d.%010llu", 
    result.parts.ipart, 
    //                                    add half the divisor
    (result.parts.fpart * 10000000000LLu + 0x40000000u/2) / 0x40000000u);

字符串
注意:小于10个小数位,舍入可能会改变整数部分。

acruukt9

acruukt92#

假设您的Cortex M3对64位整数算术有足够好的支持(支持C99或更高版本-需要64位算术),那么这段代码将展示如何完成。

#include <assert.h>
#include <inttypes.h>
#include <stdio.h>

static const uint64_t TWO_THIRTY  = 1UL << 30;
static const uint64_t ONE_BILLION = 1000000000;

static uint32_t fraction(uint32_t fpart)
{
    assert(fpart < TWO_THIRTY);
    uint64_t result = (fpart * ONE_BILLION) / TWO_THIRTY;
    assert(result < ONE_BILLION);
    return result;
}

int main(void)
{
     for (uint32_t i = 0; i < 32; i++)
         printf("%10" PRIu32 " = 0.%.9" PRIu32 "\n", i, fraction(i));
     for (uint32_t i = 64; i < TWO_THIRTY; i += (20 * i) / 19 + 1)
         printf("%10" PRIu32 " = 0.%.9" PRIu32 "\n", i, fraction(i));
     for (uint32_t i = TWO_THIRTY - 32; i < TWO_THIRTY; i++)
         printf("%10" PRIu32 " = 0.%.9" PRIu32 "\n", i, fraction(i));
     return 0;
}

字符串
我得到的输出是:

0 = 0.000000000
         1 = 0.000000000
         2 = 0.000000001
         3 = 0.000000002
         4 = 0.000000003
         5 = 0.000000004
         6 = 0.000000005
         7 = 0.000000006
         8 = 0.000000007
         9 = 0.000000008
        10 = 0.000000009
        11 = 0.000000010
        12 = 0.000000011
        13 = 0.000000012
        14 = 0.000000013
        15 = 0.000000013
        16 = 0.000000014
        17 = 0.000000015
        18 = 0.000000016
        19 = 0.000000017
        20 = 0.000000018
        21 = 0.000000019
        22 = 0.000000020
        23 = 0.000000021
        24 = 0.000000022
        25 = 0.000000023
        26 = 0.000000024
        27 = 0.000000025
        28 = 0.000000026
        29 = 0.000000027
        30 = 0.000000027
        31 = 0.000000028
        64 = 0.000000059
       132 = 0.000000122
       271 = 0.000000252
       557 = 0.000000518
      1144 = 0.000001065
      2349 = 0.000002187
      4822 = 0.000004490
      9898 = 0.000009218
     20317 = 0.000018921
     41704 = 0.000038839
     85603 = 0.000079724
    175712 = 0.000163644
    360673 = 0.000335902
    740329 = 0.000689485
   1519623 = 0.001415259
   3119227 = 0.002905006
   6402624 = 0.005962908
  13142229 = 0.012239654
  26976155 = 0.025123502
  55372108 = 0.051569294
 113658538 = 0.105852762
 233299105 = 0.217276723
 252826200 = 0.235462747
 292908132 = 0.272791955
 375181572 = 0.349415067
 544058633 = 0.506694086
 664650111 = 0.619003652
 686129076 = 0.639007497
 730217478 = 0.680068021
 820714724 = 0.764350149
1006472229 = 0.937350307
1073741792 = 0.999999970
1073741793 = 0.999999971
1073741794 = 0.999999972
1073741795 = 0.999999972
1073741796 = 0.999999973
1073741797 = 0.999999974
1073741798 = 0.999999975
1073741799 = 0.999999976
1073741800 = 0.999999977
1073741801 = 0.999999978
1073741802 = 0.999999979
1073741803 = 0.999999980
1073741804 = 0.999999981
1073741805 = 0.999999982
1073741806 = 0.999999983
1073741807 = 0.999999984
1073741808 = 0.999999985
1073741809 = 0.999999986
1073741810 = 0.999999986
1073741811 = 0.999999987
1073741812 = 0.999999988
1073741813 = 0.999999989
1073741814 = 0.999999990
1073741815 = 0.999999991
1073741816 = 0.999999992
1073741817 = 0.999999993
1073741818 = 0.999999994
1073741819 = 0.999999995
1073741820 = 0.999999996
1073741821 = 0.999999997
1073741822 = 0.999999998
1073741823 = 0.999999999


例如,可以使用bc验证计算。我把程序叫做fp71

$ fp71 | awk '{print $1}' |
> { echo 'scale=9'; echo 'd=2^30'; while read value; do echo "$value / d"; done; } |
> bc
0
0
.000000001
.000000002
.000000003
.000000004
.000000005
.000000006
.000000007
.000000008
.000000009
.000000010
.000000011
.000000012
.000000013
.000000013
.000000014
.000000015
.000000016
.000000017
.000000018
.000000019
.000000020
.000000021
.000000022
.000000023
.000000024
.000000025
.000000026
.000000027
.000000027
.000000028
.000000059
.000000122
.000000252
.000000518
.000001065
.000002187
.000004490
.000009218
.000018921
.000038839
.000079724
.000163644
.000335902
.000689485
.001415259
.002905006
.005962908
.012239654
.025123502
.051569294
.105852762
.217276723
.235462747
.272791955
.349415067
.506694086
.619003652
.639007497
.680068021
.764350149
.937350307
.999999970
.999999971
.999999972
.999999972
.999999973
.999999974
.999999975
.999999976
.999999977
.999999978
.999999979
.999999980
.999999981
.999999982
.999999983
.999999984
.999999985
.999999986
.999999986
.999999987
.999999988
.999999989
.999999990
.999999991
.999999992
.999999993
.999999994
.999999995
.999999996
.999999997
.999999998
.999999999
$


这些结果是一致的--除了我更喜欢输出中小数点前的前导零。

相关问题