#c #mingw
#c #mingw
Вопрос:
у меня проблема с тем, что scanf не читает long double в приведенном ниже коде:
(пожалуйста, извините за мой плохой английский)
#include <iostream>
#include <cstdlib>
#include <math.h>
using namespace std;
int main()
{
int n;
scanf("%d",amp;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",amp;a,amp;ha,amp;hb,amp;hc);//this is where the problem lies,
//i need to read 4 long double a,ha,hb,hc
printf("%Lf %Lf %Lf %Lfn",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 %.3Lfn",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 в коде и как это исправить.
Заранее спасибо!
Комментарии:
1. Вы забыли указать свой вопрос.
2. ну что ж, я думаю, это ясно из названия, я хочу знать, почему scanf не займет много времени в коде
3. Это не C. Я предлагаю вам придерживаться одного языка для каждого исходного файла: написание многоязычных исходных файлов не для слабонервных.
4. это dev-c , я удалю тег c, спасибо =))
5. Рассмотрите возможность использования C streams (
std::cin >> a >> ha >> hb >> hc
) вместо функции C.scanf
Ответ №1:
В Dev-c используется MinGW, который использует компилятор gcc и библиотеку времени выполнения Microsoft. К сожалению, эти компоненты расходятся во мнениях относительно базового типа, который будет использоваться long double
(я думаю, 64 против 80 или 96 бит). Windows предполагает long double
тот же размер, double
что и; gcc делает long double
больше.
Любой из вариантов допустим, но комбинация приводит к нарушению реализации на C и C .
Если вам не нужны дополнительные диапазон и точность, вы можете читать в a double
и сохранять в a long double
.
В противном случае вы можете записать или позаимствовать пользовательскую строку в long double
converter или просто использовать другую реализацию.
Редактировать
Подробнее:
Собственный компилятор Microsoft и библиотека времени выполнения согласованы в обработке long double
как 64 бита, того же размера, double
что и . Стандарт языка допускает это (он должен long double
быть как минимум таким же широким, как double
, но предъявляет одинаковые требования к обоим), но кажется странным, что он не использует преимущества 80-разрядного оборудования x86 с плавающей запятой.
gcc на x86 обрабатывает long double
как 96 бит ( sizeof (long double) == 12
). Я думаю, что только 80 из этих битов являются значимыми; дополнительные 16 бит предназначены для выравнивания.
MinGW использует gcc в качестве своего компилятора, но использует библиотеку времени выполнения Microsoft. Для большинства языковых функций это работает нормально, но несоответствие для long double
означает, что вы можете выполнять вычисления с помощью long double , но вы не можете передавать длинные двойные значения (или указатели на них) в библиотеку времени выполнения. Это ошибка в MinGW.
В MinGW есть обходные пути. Вы можете определить макрос __USE_MINGW_ANSI_STDIO
, либо передав -D__USE_MINGW_ANSI_STDIO
командную строку gcc, либо добавив строку
#define __USE_MINGW_ANSI_STDIO
к вашим исходным файлам. (Это должно быть определено раньше #include <stdio.h>
.) Комментатор paulsm4 говорит, что параметры -ansi
and -posix
заставляют MinGW использовать свою собственную соответствующую библиотеку (у меня нет причин сомневаться в этом, но в настоящее время я не могу это подтвердить). Или вы можете вызвать __mingw_printf()
напрямую.
Предполагая, что вы используете Windows, Cygwin может быть хорошей альтернативой (он использует gcc, но не использует библиотеку времени выполнения Microsoft). Или вы можете использовать long double
внутренне, но double
для ввода-вывода.
Комментарии:
1.
long double
это то, что решит компилятор; реализация не требуется для использования 80-битного формата. Компилятор и библиотека времени выполнения решили по-другому.2. Нет, вы создали конкретный examplex. Итак, вы ограничены вашими конкретными примерами. Вы не говорите об «абсолютном C». Вы говорите о MinGW на процессорах Intel. Мой комментарий касался вашего ответа, поэтому он был ограничен таким же образом.
3. @xanatos: Я думал, вы не согласны с моим ответом. Были ли вы?
4. Это всего 80 бит, но gcc выровняет 128 бит.
5. Спасибо. И из-за вашей правки я смог изменить свой голос. Еще раз спасибо 🙂
Ответ №2:
Вы счастливый счастливчик. Это не решит общую проблему long double
с MinGW, но я объясню, что происходит с вашей проблемой. Теперь, в далекий-далекий день, когда вы сможете проголосовать, я хочу, чтобы вы проголосовали. 🙂 (но я не хочу, чтобы это было помечено как правильный ответ. Это ответ на то, что вам нужно, но не на то, что вы просили (общая проблема в вашем названии scanf not taking in long double
) ).
Во-первых, решение: использовать float
. Используйте %f
в scanf
/ printf
. Результаты полностью совпадают с теми, которые указаны в качестве решения на вашем сайте. В качестве примечания, если вы хотите printf
использовать несколько десятичных знаков, сделайте так, как показано в последнем printf: %.10f
будет выводить 10 десятичных знаков после десятичного разделителя.
Во-вторых: почему у вас возникла проблема с double
s: 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, но во многих компиляторах на платформе Intel это делается. http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html ). И это объясняет, почему printf
напечатано что-то вроде -1.#IO
.
Комментарии:
1. Я заметил проблему
res
и исправил ее (float
дал значение 0.000, ноdouble
вернул отрицательный результат), прежде чем отправить исходный код на сайт. Я использовалfloat
, он дал неправильный ответ на 2-м тесте (float
дает область149604.797
, но правильный результат149604.790
). Но я лично считаю, что ваша речь о NaN очень интересна, определенно информативна и ценна. PS: конечно, я поддержу вас, когда смогу, все равно нужно еще 2 представителя.2. @minhnhat93 Если вы уже нашли это о float, то я даже не решаю вашу проблему. Но обратите внимание, что ваша проблема неразрешима: ideone.com/XZsmP ideone использует gcc в linux. 80-битный double. Все тот же результат. И обратите внимание, что кто-то еще сказал (на вашей странице):
yeah case 2 area is wrong, should be .797
3. @minhnhat93 Я рассмотрел проблему. spoj.pl/ranks/TRICENTR/lang=CS В C # есть решения, поэтому проблему можно решить с помощью float или double. Но если мы рассмотрим количество сигнификативных цифр, которые они используют, они используют удвоения. Просто попробуйте вывести 0, если res равно NaN.
4. Вот код, который я отправил в SPOJ: ideone.com/XU0uW . Он по-прежнему обрабатывает неверный результат, поэтому я думаю, что здесь есть проблема с округлением. Я постараюсь придумать менее сложное решение для вычислений, чтобы избежать этого, когда это возможно.
5. @minhnhat93 cosa l r == 2 * b * (b-sqrt(a a-hb hb)) / 3 (таким образом, вы отбрасываете
ma
, что это sqrt)
Ответ №3:
Вы можете избежать большинства проблем с преобразованием, фактически используя 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:
Не знаю, полезно ли это для вас, но вы могли бы взглянуть на это.
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;
}
Ответ №5:
К сожалению, у long double неправильная печать в GCC / Windows. Однако вы можете гарантировать, что long double по-прежнему выполняет вычисления с более высокой точностью в фоновом режиме, когда вы выполняете арифметику и тригонометрию, потому что он будет хранить не менее 80 или 96 бит.
Поэтому я рекомендую этот обходной путь для различных вещей:
-
Используйте scanf для удвоений, но после приведите их к длинным удвоениям. В любом случае вам не нужна точность при синтаксическом анализе входных данных.
double x; scanf("%lf", amp;x); // no biggie long double y = x;
-
Убедитесь, что вы используете длинные двойные версии функций в библиотеке <math.h> . Обычные просто преобразуют ваш длинный double в double, поэтому более высокая точность станет бесполезной.
long double sy = sqrtl(y); // not sqrt long double ay = 2.0L * acosl(y); // note the L-suffix in the constant
-
Чтобы распечатать свой длинный double, просто верните их в double и используйте «%lf». Double может содержать не более 15 значащих цифр, так что этого более чем достаточно. Конечно, если этого недостаточно, вам следует переключиться на Linux GCC.
printf("%.15lfn", (double) y);
Большинству программ на самом деле не нужны дополнительные цифры для вывода. Дело в том, что даже ранние цифры теряют свою точность при малейшем использовании функций sqrt или trig. ПОЭТОМУ можно сохранить double хотя бы только для печати, но важно то, что вы по-прежнему используете long double для грубых вычислений, чтобы не потерять точность, которую вы усердно вкладывали.