Scanf no toma en doble largo

Tengo un problema con scanf que no lee el doble de largo en el siguiente código:

(por favor disculpe mi pobre inglés)

#include  #include  #include  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;} } 

Aquí está la entrada:

 2 3.0 0.8660254038 0.8660254038 0.8660254038 657.8256599140 151.6154399062 213.5392629932 139.4878846649 

y aquí lo que se muestra en la línea de comando:

 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 . . . 

Quiero saber por qué scanf no tardará mucho en duplicar el código y cómo solucionarlo.

¡Gracias por adelantado!

Dev-c ++ usa MinGW, que usa el comstackdor gcc y la biblioteca de tiempo de ejecución de Microsoft. Desafortunadamente, esos componentes no están de acuerdo con el tipo subyacente que se utilizará para el long double (64 vs. 80 o 96 bits, creo). Windows asume que el long double es del mismo tamaño que el double ; gcc hace long double más grande.

Cualquiera de las dos opciones es válida, pero la combinación da como resultado una implementación de C y C ++ dañada.

Si no necesita el rango y la precisión adicionales, puede leer en un double y almacenar en un long double .

De lo contrario, puede escribir o pedir prestada una cadena personalizada a long double convertidor long double , o simplemente usar una implementación diferente.

EDITAR

Más detalles:

El propio comstackdor de Microsoft y la biblioteca de tiempo de ejecución son consistentes en tratar el long double como 64 bits, el mismo tamaño que el double . El estándar de idioma lo permite (requiere que el long double sea al menos tan ancho como el double , pero coloca los mismos requisitos en ambos), pero parece extraño que no aproveche el hardware de punto flotante de 80 bits del x86. .

gcc en x86 trata el long double como 96 bits ( sizeof (long double) == 12 ). Creo que solo 80 de esos bits son significativos; Los 16 bits adicionales son para propósitos de alineación.

MinGW usa gcc como su comstackdor, pero usa la biblioteca de tiempo de ejecución de Microsoft. Para la mayoría de las funciones de lenguaje, esto funciona bien, pero la falta de coincidencia para el long double significa que puede hacer cálculos con el doble largo, pero no puede pasar valores dobles largos (o punteros a ellos) a la biblioteca de tiempo de ejecución. Es un error en MinGW.

Hay soluciones dentro de MinGW. Puede definir la macro __USE_MINGW_ANSI_STDIO , ya sea pasando -D__USE_MINGW_ANSI_STDIO en la línea de comandos de gcc o agregando una línea

 #define __USE_MINGW_ANSI_STDIO 

a sus archivos de origen. (Debe definirse antes de #include ). Un comentarista, paulsm4, dice que las opciones -ansi y -posix hacen que MinGW use su propia biblioteca conforme (no tengo ninguna razón para dudar de esto, pero Actualmente no puedo confirmarlo). O puede llamar a __mingw_printf() directamente.

Suponiendo que está en Windows, Cygwin podría ser una buena alternativa (usa gcc, pero no usa la biblioteca de tiempo de ejecución de Microsoft). O puede usar long double internamente, pero double para E / S.

Eres un hombre con suerte. Esto no resolverá el problema general del long double de long double en MinGW, pero explicaré qué le está sucediendo a su problema. Ahora, en un día muy lejano en el que podrás votar, quiero tu voto. 🙂 (pero no quiero que esto se marque como la respuesta correcta. Es la respuesta a lo que necesita, pero no a lo que pidió (el problema general en su scanf not taking in long double títulos scanf not taking in long double )).

Primero, la solución: usar float . Utilice %f en scanf / printf . Los resultados son perfectamente iguales a los dados como la solución en su sitio. Como nota al margen, si desea printf con algunos decimales, haga lo que se muestra en la última impresión: %.10f imprimirá 10 decimales después del separador decimal.

Segundo: por qué tuvo un problema con la double s: la res=sqrt() calcula una raíz cuadrada. Usando float s, l*l+r*r-2*cosa*l*r == 0.0, usando double s es -1.0781242565371940e-010, así que algo cerca de cero PERO NEGATIVO !!! Así que el sqrt(-something) es NaN (no un número) un valor especial de double/float . Puede verificar si un número es NaN haciendo res != res . Esto se debe a NaN != NaN (pero tenga en cuenta que esto no está garantizado por los estándares C más antiguos, pero en muchos comstackdores en la plataforma Intel, hágalo en http://www.gnu.org/s/hello/manual/libc/Infinity- y -NaN.html ). Y esto explica por qué el printf imprimió algo así como -1.#IO .

Puede evitar la mayoría de sus problemas de conversión usando C ++ en lugar de usar las funciones C heredadas:

 #include  #include  #include  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(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(std::sqrt(a * a - hb * hb))) / ha; long double res = static_cast(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; } 

No sé si esto te es útil, pero podrías echarle un vistazo.

 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; } 

Lamentablemente, el doble largo tiene una impresión defectuosa en GCC / Windows. Sin embargo, puede garantizar que el doble largo todavía realice cálculos de mayor precisión en segundo plano cuando realice aritmética y trigonometría, ya que almacenaría al menos 80 o 96 bits.

Por lo tanto, recomiendo esta solución para varias cosas:

  • Use scanf en dobles, pero conviértalos en dobles largos después. De todos modos, no se necesita precisión en el análisis de entrada.

     double x; scanf("%lf", &x); // no biggie long double y = x; 
  • Asegúrese de usar versiones dobles largas de funciones en la biblioteca . Los normales simplemente emitirán su doble doble al doble, por lo que la mayor precisión se volverá inútil.

     long double sy = sqrtl(y); // not sqrt long double ay = 2.0L * acosl(y); // note the L-suffix in the constant 
  • Para imprimir su doble largo, simplemente vuélvalos a doblar y use “% lf”. El doble puede tener a lo sumo 15 dígitos significativos por lo que es más que suficiente. Por supuesto, si no es suficiente, deberías cambiar al GCC de Linux.

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

    La mayoría de los progtwigs en realidad no necesitan los dígitos adicionales para la salida. La cuestión es que incluso los primeros dígitos pierden su precisión con el menor uso de las funciones sqrt o trig . POR LO TANTO, está bien mantener el doble al menos solo para imprimir, pero lo importante es que aún usa el doble largo para los cálculos aproximados para no perder la precisión en la que trabajó arduamente para invertir.