我在下面的代码中遇到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以及如何修复它。
提前致谢!
答案 0 :(得分:12)
Dev-c ++使用MinGW,它使用gcc编译器和Microsoft运行时库。不幸的是,那些组件不同意用于long double
的基础类型(我认为64比80或96位)。 Windows假定long double
与double
的大小相同; 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函数时失去精确度。因此,保持双重至少仅用于打印是可以的,但重要的是你仍然使用长双精度进行粗略计算,以免失去你努力投资的精度。