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

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

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

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

10.05.2012, 01:35. Просмотров 1404. Ответов 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 с получением остатка от деления.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.05.2012, 01:35
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Ошибка преобразования типа (C++):

Ошибка преобразования типа в классе - C++
Дан класс, который реализует длинную арифметику с положительными\отрицательными целыми числами. Все числа одинаковой длины и их макс....

Ошибка преобразования: значение типа "float *" нельзя присвоить сущности типа "float" - C++
Помогите исправить.Значение типа &quot;float *&quot; нельзя присвоить сущности типа float void Mode2() { const int n=20,m=20 ; float a, b;...

Преобразования массива с типа int к типу char - C++
Помогите решить задачу. Требуется создать шаблон класса для преобразования массива с типа int к типу char, помогите кто чем сможет буду...

Оператор преобразования типа и его эквивалентные замены, поиск строки в текстовом файле , содержащей заданный - C++
Господа, был бы очень признателен если бы кто то помог ответить на вапросы http://cs616225.vk.me/v616225102/122f8/5kAaFEGoDn0.jpg

В массив типа double записываю целые числа (типа int), но ошибка не вылазиет! - C++
Вот программулька: #include &lt;iostream&gt; using namespace std; #include &lt;conio.h&gt; int main() { double arr={1,2,3,4,5}; ...

Ошибка преобразования - C++
Вот мой код. В общем в конце выбивает &quot;error C2664: kasat: невозможно преобразовать параметр 5 из &quot;double (__cdecl *)(double,double)&quot;...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Toshkarik
1141 / 858 / 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 );
1
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 99
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() все замечательно. Как так?
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 07:03 #18
Вещественные числа в компьютерных системах представляются приблизительно. Они не могут быть точными в отличии от целых чисел. Вы вызываете функцию log внутри exp, что только усугубляет положение. При присваивании вещественного типа целочисленному отбрасывается дробная часть. Могу предположить, что в данном случае получалось, например, число вроде 18.9234... и так далее, что при приведении давало целое 18 вместо 19. Поэтому Вам подкинул идею с функцией floor, которая округляет вещественное число до наибольшего целого не превосходящее само число. Ее часто используют для округления вещественного числа до ближайшего целого в виде
floor( val + .5 );
0
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 99
10.05.2012, 07:14  [ТС] #19
Цитата Сообщение от Toshkarik Посмотреть сообщение
Вещественные числа в компьютерных системах представляются приблизительно. Они не могут быть точными в отличии от целых чисел. Вы вызываете функцию log внутри exp, что только усугубляет положение. При присваивании вещественного типа целочисленному отбрасывается дробная часть. Могу предположить, что в данном случае получалось, например, число вроде 18.9234... и так далее, что при приведении давало целое 18 вместо 19. Поэтому Вам подкинул идею с функцией floor, которая округляет вещественное число до наибольшего целого не превосходящее само число. Ее часто используют для округления вещественного числа до ближайшего целого в виде
floor( val + .5 );
Ага, понятно, по крайне мере удалось выяснить методом научного втыка, что применение ф-ции fmod() иже с ней требует ф-ции floor(), без нее сравнения не получается.

Не по теме:

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

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

Не по теме:

Цитата Сообщение от G@leON Посмотреть сообщение
А ставить несколько спасибо можно?
За любое показавшееся Вам полезным сообщение.


Посмотрел функцию решета Эратосфена - можно свести к более простому варианту:
C++
1
2
3
4
5
6
vector< bool > vec( number );
fill( vec.begin(), vec.end(), true );
for ( size_t i = 2; i < vec.size(); i++ )
   if ( vec[ i ])
      for( size_t j = i + i; j < vec.size(); j += i )
         vec[ j ] = false;
1
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
10.05.2012, 07:25 #22
Цитата Сообщение от Avazart Посмотреть сообщение
Может человек имеет ввиду округление, а не приведение типов?
А чем округление до целого отличается от приведения дроби к целому?
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 07:28 #23
Цитата Сообщение от taras atavin Посмотреть сообщение
А чем округление до целого отличается от приведения дроби к целому?
Тем, что при округлении берется ближайшее целое, при приведении же просто отбрасывается дробная часть.
0
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
10.05.2012, 07:44 #24
Цитата Сообщение от G@leON Посмотреть сообщение
Оба значение типа long на 1 меньше, чем возвращаемые функциями значения типа double.
А при чём здесь ошибка приведения? Ошибка приведения, это когда вообще нельзя привести. А здесь погрешность округления. Твой double чуть меньше ожидаемого целого.
C++
1
2
3
4
5
6
int x;
int y;
float z;
z=2.5;
x=z;// Округление вниз, x=2
y=z+0.5;// Округление по математическим правилам, y=3
Добавлено через 8 минут
Цитата Сообщение от Toshkarik Посмотреть сообщение
Тем, что при округлении берется ближайшее целое, при приведении же просто отбрасывается дробная часть.
Существует как минимум 4 способа округления: вниз, вверх, по математическим правилам и так называемое банкирское, по правилам которого если дробная часть точно равна 0.5, то округляют к ближайшему чётному, а в остальных случаях к ближайшему целому, при округлении вниз дробная часть отбрасывается, при округлении вверх при ненулевой дробной части инкремируется целая, а при нулевой сохраняется и после этого отбрасывается дробная часть, а оператор приведения типа может быть написан как угодно и предусматривать какое нибудь вообще пятое округление. В любом случае обнуление младших разрядов в какой либо системе счисления есть округление (округлять можно и до сотен, и до сотых), а приведение к целому всегда обнуляет все разряды с весами меньше единицы, что есть округление до целого. То, что встроенные типы принято приводить именно округлением вниз, сути не меняет.

Добавлено через 6 минут
Цитата Сообщение от G@leON Посмотреть сообщение
Я так понимаю, задача вылазит несколько другим боком. Нужно как то умудрится возвести в степень n и n-1 число v_1, а результат потом делить на n с получением остатка от деления.
Если и основание, и показатель целые, то зачем возводить в степень через экспоненту? Для данного случая степень определена, как произведение одинаковых множителей, так и делай.
1
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 07:46 #25
Думаю, тут уместно обсуждение математического округления а не каких то там "банкирских" и тд.
Приведение типа, как я считаю, никак не связанно с округлением.
Цитата Сообщение от taras atavin Посмотреть сообщение
написан как угодно
Не как угодно, отбрасывается именно дробная часть.
0
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
10.05.2012, 07:51 #26
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
long int degree(long int a, unsigned int n)// a в степени n
{
 int n1;
 if (n==1)
 {
  return a;
 }
 if (n==0)
 {
  return 1;
 }
 n1=n/2;
 return (degree(a, n1)*degree(a, n-n1)); 
}
, или
C++
1
2
3
4
5
6
7
8
9
long int degree(long int a, unsigned int n)// a в степени n
{
 int r;
 for (r=1; n>0; --n)
 {
  r*=a;
 }
 return r; 
}
Добавлено через 3 минуты
Цитата Сообщение от Toshkarik Посмотреть сообщение
Не как угодно, отбрасывается именно дробная часть.
Как угодно. Конкретный способ принят только для стандартных типов и является всего лишь вопросом выбора авторов стандарта. Для своих типов ты можешь сделать даже так: если дробная часть строго меньше 0.5, то вверх, иначе вниз. И это тоже будет округление. Или можешь сделать математическое округление до кратного трём.
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 07:54 #27
При чем тут не стандартные типы? Вы тут видите приведение не стандартных типов? Для стандартных типов точно указано, что получится в итоге, и это никак не связанно с округлением. Это форум С++, если Вы вдруг упустили это из виду.
0
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
10.05.2012, 08:03 #28
Для стандартных был выбран один из способов округления, выбор закрепили. И всего делов. Приведение стандартного вещественного к целому, это округление вниз до целого, а не что то абсолютно новое.
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
10.05.2012, 08:07 #29
Я же считаю, что данный способ был выбран исходя из природы чисел. Целое на то и целое, что в нем нет дробной части, поэтому она отбрасывается, и это не округление.
0
G@leON
6 / 6 / 1
Регистрация: 02.06.2009
Сообщений: 99
10.05.2012, 08:18  [ТС] #30
За решето спасибо, удобный способ, по поводу приведения типов, это именно ошибка приведения, просто это не ошибка синтаксиса, а ошибка компиляции некрасивой логики. И да, именно с округлением она и связана, так что в формулировке не вижу повода сомневаться.

По поводу параметра ссылки, а какая разница, передаете вы через параметр-ссылку, или просто возвращаете значение? Если вопрос удобства, то мне удобней через параметр-ссылку (либо параметр-указатель). Мне так логика понятней кажется.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.05.2012, 08:18
Привет! Вот еще темы с ответами:

Ошибка преобразования типов - C++
В чем именно я ошибся,если код ошибки #include &lt;iostream&gt; #include &lt;stdlib.h&gt; #include &lt;string&gt; #include &lt;ctype.h&gt; using...

ошибка преобразования char - C++
помогите найти ошибку(или исправить): #include&lt;iostream&gt; #include&lt;string.h&gt; #include&lt;conio.h&gt; #include&lt;stdio.h&gt; ...

Ошибка преобразования класса - C++
Добрый день! Уважаемые, помогите пожалуйста найти ошибку. #include &lt;iostream&gt; #include &lt;stdio.h&gt; #include &lt;string.h&gt; #include...

Ошибка в функции преобразования времени - C++
Как можно или нужно написать программу, которая, при вводе с клавиатуры, делает преобразования времени при помощи двух функций. Одна...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
10.05.2012, 08:18
Ответ Создать тему
Опции темы

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