Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 4.64
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 97
#1

Ошибка преобразования типа - C++

10.05.2012, 01:35. Просмотров 1360. Ответов 32
Метки нет (Все метки)

Задача состояла в следующем: реализация алгоритма проверки n на простоту, используя малую теорему Ферма. В силу недостаточного опыта и позднего времени накумекал следующий код с пояснениями:

В качестве 1 из параметров, передаваемых функциям, выступает маркер простоты.
Это параметр-ссылка на переменную логического типа.
Значение маркера = true после выполнения подтверждает простоту проверяемого числа.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int gcd(int v_1, int v_2){
    while (v_2){
        int temp = v_2;
        v_2 = v_1 % v_2;
        v_1 = temp;
    }
    return v_1;
}
 
void ferma_lt_test(bool &prime_marker, int n){
    prime_marker = true;
    if (n<1){
        prime_marker = false;
        cout << "n is not natural" << endl;
    }
    if (n>2) {
        int v_1 = 2;
        while ((gcd(n,v_1)) != 1)
            v_1++;
        double deg_v = n, base_v = v_1;
        long l_v1 = exp(deg_v * log(base_v)), l_v2 = exp((deg_v - 1) * log(base_v));
        l_v1 %= n;
        l_v2 %= n;
        if ((l_v1 != v_1) || (l_v2 != 1))
            prime_marker = false;
    }
}
Здесь ф-ция gcd(v_1,v_2) - нахождение НОД. Вторая функция: Тест малой теоремой Ферма.

Ошибка заключается собственно в том, что при преобразовании double в long в строке:
C++ (Qt)
1
long l_v1 = exp(deg_v * log(base_v)), l_v2 = exp((deg_v - 1) * log(base_v));
Оба значение типа long на 1 меньше, чем возвращаемые функциями значения типа double. Притом, данная ошибка вылезает для чисел до 19 включительно. Число 23, как ни странно, проверяется. Помогите исправить.

Соответственно, число 31 уже выходит за границу допустимого диапазона. Было бы неплохо, так же, услышать подсказку по увеличению допустимого диапазона (например, имеется ли стандартный модуль(заголовок) длинной математики в C++, а если нет, то какой лучше и где найти...).

Добавлено через 52 минуты
После проверки на различные варианты преобразования выяснил, что они не помогают, ни преобразование в стиле C, не преобразование в стиле С++ (cast которые). Конечно, проблему можно разрешить проверкой на принадлежность к определенному числу (типа if n < 19 ... то прибавлять к функции +1), но это вообще не выход. Так что проблему надо решать альтернативным методом. Каким, не знаю.

Я так понимаю, задача вылазит несколько другим боком. Нужно как то умудрится возвести в степень n и n-1 число v_1, а результат потом делить на n с получением остатка от деления.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.05.2012, 01:35     Ошибка преобразования типа
Посмотрите здесь:

ошибка преобразования char C++
C++ Ошибка преобразования типа в классе
C++ Ошибка преобразования
Ошибка в функции преобразования Фурье C++
Динамический массив структур. Ошибка преобразования типов C++
Ошибка "преобразования" параметра C++
C++ Оператор преобразования типа и его эквивалентные замены, поиск строки в текстовом файле , содержащей заданный
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Avazart
7063 / 5240 / 262
Регистрация: 10.12.2010
Сообщений: 23,049
Записей в блоге: 17
10.05.2012, 05:18     Ошибка преобразования типа #2
Что такое exp() и где оно живет?
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 97
10.05.2012, 05:32  [ТС]     Ошибка преобразования типа #3
Она из заголовка <math.h>
Давай так. Что бы проще было, вкладываю код юнита, заголовка и собственно main.
Вложения
Тип файла: rar Библиотеки проверки на простоту.rar (1.5 Кб, 5 просмотров)
Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 05:48     Ошибка преобразования типа #4
Avazart, exp()
Это вот эта теорема?
Avazart
7063 / 5240 / 262
Регистрация: 10.12.2010
Сообщений: 23,049
Записей в блоге: 17
10.05.2012, 06:02     Ошибка преобразования типа #5
У мня компилится без ошибок...

Добавлено через 7 минут
Toshkarik, Само выражение просто страшное, напомнило чем то шаблоны STL,подумал что exp() самописная а не экспонента (время позднее или точнее раннее)

Добавлено через 1 минуту
C++
1
2
long l_v1 = exp(deg_v * log(base_v));
long l_v2 = exp((deg_v - 1) * log(base_v));
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 97
10.05.2012, 06:07  [ТС]     Ошибка преобразования типа #6
Компилитс без ошибок, я вообщето писал что все ОК.
Ошибка в преобразовании. Преобразование он делает, но теряет 1.

Там где для компиляции я в выходной поток вставил результаты возведения:
void ferma_lt_test(bool &prime_marker, int n){
prime_marker = true;
if (n<1){
prime_marker = false;
cout << "n is not natural" << endl;
}
if (n>2) {
int v_1 = 2;
while ((gcd(n,v_1)) != 1)
v_1++;
double deg_v = n, base_v = v_1;
long l_v1 = exp(deg_v * log(base_v)), l_v2 = exp((deg_v - 1) * log(base_v));
cout << v_1 << " " << (l_v1) << " " << l_v2 << endl; //ЗДЕСЬ
l_v1 %= n;
l_v2 %= n;
if ((l_v1 != v_1) || (l_v2 != 1))
prime_marker = false;
}
}
Сделай вот так:
C++ (Qt)
1
cout << exp(deg_v * log(base_v)) << " " << (l_v1) << " " << l_v2 << endl;
И да, код в модуле уже модифицированный. Надо в модуль вставить код, который выше.
Avazart
7063 / 5240 / 262
Регистрация: 10.12.2010
Сообщений: 23,049
Записей в блоге: 17
10.05.2012, 06:14     Ошибка преобразования типа #7
Что значит "1"?

Добавлено через 5 минут
Поидее так должно быть
C++
1
2
long double l_v1 = (exp(deg_v * log(base_v)));
long double l_v2 = (exp((deg_v - 1) * log(base_v)));
если хочишь большую точность
Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 06:16     Ошибка преобразования типа #8
Так Вы уж определитесь, с какими типами работаете, не удивительно, что есть погрешность при преобразовании вещественного типа в целочисленный.
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 97
10.05.2012, 06:19  [ТС]     Ошибка преобразования типа #9
Мне дальше надо делить с получением остатка. Поэтому мне надо получить целочисленное.
Ни 1 из вещественных типов не обрабатывается оператором %.

Единица в смысле в значении. Например 13.
2^13 это 8192, а результат после long l_v1 = exp(deg_v * log(base_v)) равен 8191.

И я понимаю, что это некрасиво. С точки зрения машины все правильно, но я то понимаю, что есть погрешность при преобразовании вещественного типа в целочисленный. Просто тип double не делится с остатком))
Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 06:21     Ошибка преобразования типа #10
Для этого есть функция fmod().
Avazart
7063 / 5240 / 262
Регистрация: 10.12.2010
Сообщений: 23,049
Записей в блоге: 17
10.05.2012, 06:21     Ошибка преобразования типа #11
Может человек имеет ввиду округление, а не приведение типов?
Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 06:22     Ошибка преобразования типа #12
А чем при возведении в степень не устроила функция pow()?
Avazart
7063 / 5240 / 262
Регистрация: 10.12.2010
Сообщений: 23,049
Записей в блоге: 17
10.05.2012, 06:24     Ошибка преобразования типа #13
Выглядит не так страшно
Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 06:27     Ошибка преобразования типа #14

Не по теме:

Avazart,


G@leON, если хотите сохранить свой код, то попробуйте сделать вот так
C++
1
2
long l_v1 = floor( exp(deg_v * log(base_v)) + .5 ),
     l_v2 = floor( exp((deg_v - 1) * log(base_v)) + .5 );
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 97
10.05.2012, 06:36  [ТС]     Ошибка преобразования типа #15
Во, fmod - то, что нужно.
floor - это тоже хорошо.
А функция pow(), она конечно хороша, просто такая форма возведения мне понятна. А код pow() мне смотреть лень. Хотя разницы нет (наверное))).
Всем СПАСИБО
Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 06:39     Ошибка преобразования типа #16
Цитата Сообщение от G@leON Посмотреть сообщение
Хотя разницы нет (наверное)
Скорей всего есть. Использование pow() имеет вид:
double pow( base, exponent );
То-есть в Вашем случае просто нужно было написать
C++
1
long l_v1 = pow( v_1, n );
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 97
10.05.2012, 06:52  [ТС]     Ошибка преобразования типа #17
Цитата Сообщение от Toshkarik Посмотреть сообщение
Скорей всего есть. Использование pow() имеет вид:
double pow( base, exponent );
То-есть в Вашем случае просто нужно было написать
C++
1
long l_v1 = pow( v_1, n );
Кстати да, попробовал предсавленный код, он тоже верный. Но......
И использовать его проще, что б нафиг на парится)) Оставлю с pow(). Все таки странно. exp() преобразуется с потерей 1 в значении. А после pow() все замечательно. Как так?
Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 07:03     Ошибка преобразования типа #18
Вещественные числа в компьютерных системах представляются приблизительно. Они не могут быть точными в отличии от целых чисел. Вы вызываете функцию log внутри exp, что только усугубляет положение. При присваивании вещественного типа целочисленному отбрасывается дробная часть. Могу предположить, что в данном случае получалось, например, число вроде 18.9234... и так далее, что при приведении давало целое 18 вместо 19. Поэтому Вам подкинул идею с функцией floor, которая округляет вещественное число до наибольшего целого не превосходящее само число. Ее часто используют для округления вещественного числа до ближайшего целого в виде
floor( val + .5 );
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 97
10.05.2012, 07:14  [ТС]     Ошибка преобразования типа #19
Цитата Сообщение от Toshkarik Посмотреть сообщение
Вещественные числа в компьютерных системах представляются приблизительно. Они не могут быть точными в отличии от целых чисел. Вы вызываете функцию log внутри exp, что только усугубляет положение. При присваивании вещественного типа целочисленному отбрасывается дробная часть. Могу предположить, что в данном случае получалось, например, число вроде 18.9234... и так далее, что при приведении давало целое 18 вместо 19. Поэтому Вам подкинул идею с функцией floor, которая округляет вещественное число до наибольшего целого не превосходящее само число. Ее часто используют для округления вещественного числа до ближайшего целого в виде
floor( val + .5 );
Ага, понятно, по крайне мере удалось выяснить методом научного втыка, что применение ф-ции fmod() иже с ней требует ф-ции floor(), без нее сравнения не получается.

Не по теме:

А ставить несколько спасибо можно? А то меня порадовало конечно .

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.05.2012, 07:23     Ошибка преобразования типа
Еще ссылки по теме:

C++ Ошибка: "Значение типа float нельзя присвоить сущности типа int"
C++ Ошибка преобразования класса
Ошибка в функции преобразования времени C++
Преобразования массива с типа int к типу char C++
Ошибка преобразования типов C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
taras atavin
Ушёл с форума.
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
10.05.2012, 07:23     Ошибка преобразования типа #20
Цитата Сообщение от G@leON Посмотреть сообщение
адача состояла в следующем: реализация алгоритма проверки n на простоту, используя малую теорему Ферма. В силу недостаточного опыта и позднего времени накумекал следующий код с пояснениями:
В качестве 1 из параметров, передаваемых функциям, выступает маркер простоты.
Это параметр-ссылка на переменную логического типа.
Значение маркера = true после выполнения подтверждает простоту проверяемого числа.
Зачем здесь лишний параметр? Проще возвращать по имени самой функции ретоном и не мучаться.
Yandex
Объявления
10.05.2012, 07:23     Ошибка преобразования типа
Ответ Создать тему
Опции темы

Текущее время: 05:57. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru