scanf没有进入长双

时间:2011-10-19 14:32:39

标签: c++ mingw

我在下面的代码中遇到scanf没有读取long double的问题:

(请原谅我可怜的英语)

#include <iostream>
#include <cstdlib>
#include <math.h>
using namespace std;
int main()
    {
    int n;
    scanf("%d",&n);
    long double a,b,c,ha,hb,hc,ma,cosa,r,l,res,area;
    for (int i=0;i<n;i++)
    {
        scanf("%Lf %Lf %Lf %Lf",&a,&ha,&hb,&hc);//this is where the problem lies,
  //i need to read 4 long double a,ha,hb,hc
        printf("%Lf %Lf %Lf %Lf\n",a,ha,hb,hc);//but it returned wrong answer so
  //i used printf to check, ps: the code works with float but not with double or
  //long double
        ha*=3;hb*=3;hc*=3;
        c=(a*ha)/hc; b=(a*ha)/hb;
        ma=sqrt(0.5*b*b+0.5*c*c-0.25*a*a);
        cosa=ha/ma;
        r=(2*ma)/3;
        l=b*(b-sqrt(a*a-hb*hb))/ha;
        res=sqrt(l*l+r*r-2*cosa*l*r);
        area=a*ha/2;
        printf("%.3Lf %.3Lf\n",area,res);
    }
    system("PAUSE");
    return 0;}
}

这里是输入:

2
3.0 0.8660254038 0.8660254038 0.8660254038
657.8256599140 151.6154399062 213.5392629932 139.4878846649

以及命令行中显示的内容:

2
3.0 0.8660254038 0.8660254038 0.8660254038
3.000000 -4824911833695204400000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000.000000 284622047019579100000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000.0
00000 0.866025
-2.000 0.000
657.8256599140 151.6154399062 213.5392629932 139.4878846649
657.825660 -0.000000 28969688850499604000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000.000000 213.539263
-2.000 0.000
Press any key to continue . . .

我想知道为什么scanf不会在代码中使用long double以及如何修复它。

提前致谢!

5 个答案:

答案 0 :(得分:12)

Dev-c ++使用MinGW,它使用gcc编译器和Microsoft运行时库。不幸的是,那些组件不同意用于long double的基础类型(我认为64比80或96位)。 Windows假定long doubledouble的大小相同; gcc使long double更大。

任何一种选择都是有效的,但这种结合会导致C和C ++实施失败。

如果您不需要额外的范围和精确度,可以阅读double并存储到long double

否则,您可以将自定义字符串写入或借用long double转换器,或者只使用其他实现。

修改

更多详情:

Microsoft自己的编译器和运行时库将long double视为64位,与double大小相同。语言标准允许这样做(它要求long double 至少double一样宽,但对两者都要求相同的要求,但它似乎很奇怪不要利用x86的80位浮点硬件。

x86上的gcc将long double视为96位(sizeof (long double) == 12)。我认为这些比特中只有80个是重要的;额外的16位用于对齐目的。

MinGW使用gcc作为其编译器,但使用Microsoft的运行时库。对于大多数语言功能,这工作正常,但long double的不匹配意味着您可以使用long double执行计算,但是您不能传递long double值(或指向它们的指针)到运行时库。这是MinGW中的一个错误。

MinGW中有解决方法。您可以通过在gcc命令行上传递__USE_MINGW_ANSI_STDIO或添加一行来定义宏-D__USE_MINGW_ANSI_STDIO

#define __USE_MINGW_ANSI_STDIO

到您的源文件。 (必须在 #include <stdio.h>之前定义。)评论者paulsm4表示-ansi-posix选项会导致MinGW使用自己的符合性库(我没有理由怀疑这一点,但我目前无法证实这一点。或者您可以直接致电__mingw_printf()

假设您使用的是Windows,Cygwin可能是一个不错的选择(它使用gcc,但它不使用Microsoft的运行时库)。或者您可以在内部使用long double,但{/ 1}}用于I / O.

答案 1 :(得分:4)

你是一个幸运的幸运儿。这不能解决MinGW上long double的一般问题,但我会解释你的问题发生了什么。现在,在你能够投票的遥远的一天,我想要你的upvote。 :-)(但我不希望将其标记为正确的答案。这是对您所需要的响应,而不是您所问的内容(标题scanf not taking in long double中的一般问题))。

首先,解决方案:使用float。在%f / scanf中使用printf。结果完全等同于您网站中的解决方案。作为旁注,如果你想printf有一些小数,请按照最后一个printf中的显示进行操作:%.10f将在小数点分隔符后打印10位小数。

第二:为什么double出现问题:res=sqrt()计算平方根。使用float s,l*l+r*r-2*cosa*l*r == 0.0,使用double s,它是-1.0781242565371940e-010,所以接近零但是负面的东西!因此,sqrt(-something)NaN(非数字)特殊值double/float。您可以通过NaN检查号码是否为res != res。这是因为NaN != NaN(但请注意,旧版C标准并不能保证这一点,但在英特尔平台的许多编译器中都可以做到这一点。http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html)。这解释了为什么printf打印了类似-1.#IO的内容。

答案 2 :(得分:0)

不知道这对你有用,但你可以看一下。

long long int XDTOI(long double VALUE)
{
    union
    {
        long double DWHOLE;
        struct
        {
            unsigned int DMANTISSALO:32;
            unsigned int DMANTISSAHI:32;
            unsigned int DEXPONENT:15;
            unsigned int DNEGATIVE:1;
            unsigned int DEMPTY:16;
        } DSPLIT;
    } DKEY;
    union
    {
        unsigned long long int WHOLE;
        struct
        {
            unsigned int ARRAY[2];
        } SPLIT;
    } KEY;
    int SIGNBIT,RSHIFT;
    unsigned long long int BIGNUMBER;
    long long int ACTUAL;

    DKEY.DWHOLE=VALUE; SIGNBIT=DKEY.DSPLIT.DNEGATIVE; 
    RSHIFT=(63-(DKEY.DSPLIT.DEXPONENT-16383));
    KEY.SPLIT.ARRAY[0]=DKEY.DSPLIT.DMANTISSALO;
    KEY.SPLIT.ARRAY[1]=DKEY.DSPLIT.DMANTISSAHI;
    BIGNUMBER=KEY.WHOLE;
    BIGNUMBER>>=RSHIFT;
    ACTUAL=((long long int)(BIGNUMBER));
    if(SIGNBIT==1) ACTUAL=(-ACTUAL);
    return ACTUAL;
}

答案 3 :(得分:0)

您可以通过实际使用C ++而不是使用旧版C函数来避免大多数转换问题:

#include <algorithm>
#include <iostream>
#include <iterator>

int main()
{
    long double a = 0.0;

    long double ha = 0.0;
    long double hb = 0.0;
    long double hc = 0.0;
    int n = 0;

    std::cout << "Enter Count:  ";
    std::cin >> n;

    for (int i = 0; i < n; i++)
    {
        std::cout << "Enter A, Ha, Hb, Hc:  ";
        std::cin >> a >> ha >> hb >> hc;
        std::cout.precision(10);
        std::cout << "You Entered:  " 
                  << a  << " " << ha << " " << hb << " " << hc << std::endl;
        ha *= 3;
        hb *= 3;
        hc *= 3;
        long double c = (a * ha) / hc;
        long double b = (a * ha) / hb;
        long double ma = static_cast<long double>(std::sqrt(0.5 * b * b + 0.5 * c * c - 0.25 * a * a));
        long double cosa = ha / ma;
        long double r = (2 * ma) / 3;
        long double l = b * (b - static_cast<long double>(std::sqrt(a * a - hb * hb))) / ha;
        long double res = static_cast<long double>(std::sqrt(l * l + r * r - 2 * cosa * l * r));
        long double area = a * ha / 2.0;
        std::cout << "Area = " << area  << std::endl;
    }

    return 0;
}

答案 4 :(得分:0)

可悲的是,long double在GCC / Windows中打印错误。但是,当你进行算术和三角测量时,你可以保证长双在后台仍然可以进行更高精度的计算,因为它可以存储至少80或96位。

因此,我推荐这种解决方法:

  • 在双打上使用 scanf ,但之后将其转换为长双打。无论如何,你不需要精确的输入解析。

    double x;
    scanf("%lf", &x); // no biggie
    long double y = x;
    
  • 确保在&lt; math.h&gt; 库中使用long double版本的函数。正常的只会将你的长双精度加倍,所以更高的精度将变得无用。

    long double sy = sqrtl(y);        // not sqrt
    long double ay = 2.0L * acosl(y); // note the L-suffix in the constant
    
  • 要打印长双,只需将它们重新加倍并使用“%lf”。 Double最多可以包含15位有效数字,因此绰绰有余。当然,如果还不够,你应该切换到Linux的GCC。

    printf("%.15lf\n", (double) y);
    

    大多数程序实际上不需要输出的额外数字。问题是,即使是早期的数字也会在最轻微的使用sqrt或trig函数时失去精确度。因此,保持双重至少仅用于打印是可以的,但重要的是你仍然使用长双精度进行粗略计算,以免失去你努力投资的精度。