Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 打印浮点数的整数部分_C_String_Floating Point_Floating Accuracy - Fatal编程技术网

C 打印浮点数的整数部分

C 打印浮点数的整数部分,c,string,floating-point,floating-accuracy,C,String,Floating Point,Floating Accuracy,我正在尝试找出如何在不使用库函数的情况下打印浮点数字。事实证明,打印浮点数的小数部分相当容易。打印不可分割的部分比较困难: static const int base = 2; static const char hex[] = "0123456789abcdef"; void print_integral_part(float value) { assert(value >= 0); char a[129]; // worst case is 128 digits fo

我正在尝试找出如何在不使用库函数的情况下打印浮点数字。事实证明,打印浮点数的小数部分相当容易。打印不可分割的部分比较困难:

static const int base = 2;
static const char hex[] = "0123456789abcdef";

void print_integral_part(float value)
{
    assert(value >= 0);
    char a[129]; // worst case is 128 digits for base 2 plus NUL
    char * p = a + 128;
    *p = 0;
    do
    {
        int digit = fmod(value, base);
        value /= base;
        assert(p > a);
        *--p = hex[digit];
    } while (value >= 1);
    printf("%s", p);
}
打印
FLT_MAX
的组成部分在基2和基16上可以完美地工作:

11111111111111111111111100000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000 (base 2)

ffffff00000000000000000000000000 (base 16)
但是,以10为基数打印会导致前7位之后出现错误:

340282368002860660002286082464244022240 (my own function)
340282346638528859811704183484516925440 (printf)
我想这是除以10的结果。如果我使用double而不是float,效果会更好:

340282346638528986604286022844204804240 (my own function)
340282346638528859811704183484516925440 (printf)
(如果您不相信
printf
,请在Wolfram Alpha中输入
2^128-2^104
。这是正确的。)


现在,如何打印正确的结果?它是否在内部使用了一些bigint工具?还是我缺少了一些浮点技巧?

我相信问题在于
value/=base。不要忘记10在二进制中不是一个有限分数,因此这个计算永远是不正确的。我还假设由于同样的原因,
fmod
中会出现一些错误

printf
将首先计算整型部分,然后将其转换为十进制(如果我得到了您正确计算整型部分的方法)。

/Edit:Read first。这一结果来自于

要查看
value/=base
操作对值造成的混乱程度,请执行以下操作:

input : 340282346638528859811704183484516925440.000000
interm: 34028234663852885981170418348451692544.000000
interm: 3402823466385288480057879763104038912.000000
interm: 340282359315034876851393457419190272.000000
interm: 34028234346940236846450271659753472.000000
interm: 3402823335658820218996583884128256.000000
interm: 340282327376181848531187106054144.000000
interm: 34028232737618183051678859657216.000000
interm: 3402823225404785588136713388032.000000
interm: 340282334629736780292710989824.000000
interm: 34028231951816403862828351488.000000
interm: 3402823242405304929106264064.000000
interm: 340282336046446683592065024.000000
interm: 34028232866774907300610048.000000
interm: 3402823378911210969759744.000000
interm: 340282332126513595416576.000000
interm: 34028233212651357863936.000000
interm: 3402823276229139890176.000000
interm: 340282333252413489152.000000
interm: 34028234732616232960.000000
interm: 3402823561222553600.000000
interm: 340282356122255360.000000
interm: 34028235612225536.000000
interm: 3402823561222553.500000
interm: 340282366859673.625000
interm: 34028237357056.000000
interm: 3402823735705.600098
interm: 340282363084.799988
interm: 34028237619.200001
interm: 3402823680.000000
interm: 340282368.000000
interm: 34028236.800000
interm: 3402823.600000
interm: 340282.350000
interm: 34028.234375
interm: 3402.823438
interm: 340.282349
interm: 34.028235
interm: 3.402824
interm: 0.340282
result: 340282368002860660002286082464244022240

当有疑问时,向其抛出更多printfs;)

浮点到字符串转换的工作机制似乎是
dtoa()
函数。请参见newlib中的,了解他们是如何做到这一点的

现在,printf如何打印正确的结果

我认为这是接近魔术。至少源头看起来像某种黑暗的咒语

它是否在内部使用了一些bigint工具

是,在链接的源文件中搜索
\u Bigint

还是我缺少了一些浮点技巧


很可能。

根据IEEE单精度浮点实现,浮点变量在任何时候仅存储24位数据。这意味着浮点数最多只能存储7位十进制数字

数字的其余部分存储在指数中。FLT_最大值初始化为3.402823466e+38F。因此,在第10个精度之后,应该打印哪个数字在任何地方都没有定义

因此,最初我们有许多有效数字3402823466 所以在第一组之后,我们只有0402823466 因此,系统需要去掉左边的0,并在右边引入一个新的数字。 在理想整数除法中,它是0。 因为您正在进行浮点除法(value/=base;),所以系统将获取一些其他数字来填充该位置


因此,在我看来,printf可以将上面可用的有效数字分配给一个整数,并使用它。

让我们再解释一次。在整数部分打印(精确)后,没有任何舍入,除了向0切去之外,现在是小数位的时间了

从包含二进制零的一串字节开始(比如100作为起始值)。如果fp值小数点右侧的第一位被设置,这意味着0.5(2^-1或1/(2^1)是分数的一个组成部分。因此,将5添加到第一个字节。如果将下一位设置为0.25(2^-2或1/(2^2))是分数的一部分,则将5添加到第二个字节,并将2添加到第一个字节(哦,不要忘记进位,它们会发生-初中数学)。下一位表示0.125,因此第三个字节加5,第二个字节加2,第一个字节加1。依此类推:

      value          string of binary 0s
start 0              0000000000000000000 ...
bit 1 0.5            5000000000000000000 ...
bit 2 0.25           7500000000000000000 ...
bit 3 0.125          8750000000000000000 ...
bit 4 0.0625         9375000000000000000 ...
bit 5 0.03125        9687500000000000000 ...
bit 6 0.015625       9843750000000000000 ...
bit 7 0.0078125      9921875000000000000 ...
bit 8 0.00390625     9960937500000000000 ...
bit 9 0.001953125    9980468750000000000 ...
...
我是手工做的,所以我可能遗漏了一些东西,但在代码中实现这一点是微不足道的

所以对于那些“不能用浮点得到精确结果”的人来说,他们不知道他们在这里所说的是什么,这证明了浮点分数值是完全精确的。精确得令人痛苦。但是二进制的

对于那些花时间了解其工作原理的人来说,更高的精度是很容易达到的。至于其他人……我想他们不会继续浏览论坛,寻找一个以前已经回答过无数次的问题的答案,老实说,他们相信他们已经发现了“破浮点数”(或者随便他们怎么称呼)每天发布同一问题的新变体


“接近魔法”,“黑暗咒语”-太搞笑了!

这个程序适合你

#include<stdio.h>
int main()
{
    float num;
    int z;
    scanf("%f",&num);
    z=(int)num;
    printf("the integral part of the floating point number is %d",z);
}
#包括
int main()
{
浮点数;
intz;
scanf(“%f”、&num);
z=(int)num;
printf(“浮点数的整数部分是%d”,z);
}

为什么不看看一些
printf()
实现?@wilx我不想作弊;)准确高效地打印浮点值很难,除非是2的幂的基(对于二进制浮点,是2的幂和十进制浮点表示的5的幂的乘积)。在基数10中,如果使用大整数(
m*2^(-p)==(m*5^p)*10^(-p)
),则变得相当容易。如果不使用大整数,您可以首先获得二进制表示形式,然后将其转换为十进制,其中整数部分使用a,小数部分使用类似的表示形式。但这不是很有效。您可能会发现我关于此主题的文章很有趣--从这里开始:@Rick Regan:它精确地打印340282368002860660002286082642440240 a问题中的s。我认为这部分是正确的。如果原始数字本身可以被10整除,那么被10整除将给出正确的答案。然而,情况不太可能是这样。而且,只有254位精度,大约是7位小数,所以在被10整除7次之后,所有赌注都被取消了。@JeremyP我认为如果你扭动te“double p=10.0;然后计算p/=10.0;p将接近1.0,但并不精确(除非编译器进行一些优化)。@Jerem
#include<stdio.h>
int main()
{
    float num;
    int z;
    scanf("%f",&num);
    z=(int)num;
    printf("the integral part of the floating point number is %d",z);
}