Наибольший простой фактор - C ++

Я пытаюсь найти наибольший простой множитель числа 600851475143. Мой код работает с меньшими числами, которые я тестирую (ниже 100). Однако при встрече с 600851475143 он возвращает 4370432, определенно не простое число. Есть идеи, что может быть не так с моим кодом?

#include <iostream>
#include <time.h>
#include <math.h>

using namespace std;

int main()
{

int num;
int largest;
int count;

cout<<"Please enter a number to have its Largest Prime Factor found"<<endl;
cin>>num;
num = 600851475143;

for (int factor = 1; factor <= num; factor++)
{
    if (num % factor == 0)
    {
        count = 0;
        for (int primetest=2; count == 0 && factor > primetest ; primetest++) 
        {
            if (factor % primetest == 0)
            count ++;    
            //endif
        }
        if (count == 0)
        largest = factor;
        //endif
    }       

}//endif
cout<<largest<<endl;
system("PAUSE");
}

person user894575    schedule 15.08.2011    source источник
comment
Вы найдете множество обсуждений проблемы 3 проекта Эйлера при поиске числа, которое нужно разложить на множители, stackoverflow .com / search? tab = newest & q = 600851475143   -  person Lutz Lehmann    schedule 08.03.2014


Ответы (4)


num = 600851475143;

Здесь происходит целочисленное переполнение. Размер num недостаточно велик, чтобы вместить указанное вами значение.

Используйте uint64_t.

#include <cstdint>  //must include this!

uint64_t num = 600851475143;

Прочтите это: cstdint

person Nawaz    schedule 15.08.2011
comment
Хорошо, это объяснило бы это. Если вы не возражаете, не могли бы вы предоставить тип данных без плавающей запятой, который мог бы содержать такое значение? - person user894575; 15.08.2011
comment
@ user894575: Смотри мой ответ сейчас. - person Nawaz; 15.08.2011
comment
целочисленный литерал должен быть соответственно большим: 600851475143ull - person Gene Bushuyev; 15.08.2011
comment
@Gene: Но теперь вы предполагаете существование 64-битной unsigned long long? При таком предположении зачем возиться с заголовком cstdint? - person visitor; 15.08.2011
comment
Всегда устанавливайте свой компилятор на самые высокие уровни разумных предупреждений, тогда он сообщит вам о таких переполнениях. В C99 и C ++ 11 есть необязательные целочисленные типы фиксированной ширины, такие как uint64_t, которые могут быть полезны. Используйте std :: numeric_limits ‹T› :: digits10, чтобы выяснить, подходит ли тип для ваших нужд. Если вам нужно больше цифр, используйте библиотеку произвольной точности, например gmp. - person PlasmaHH; 15.08.2011

С кодом довольно много серьезных проблем, поэтому я хочу показать более полное решение. Основная проблема в том, что у него нет проверки ввода! Хороший код должен быть правильным на всех входах, которые он не отклоняет. Итак, я включил правильное чтение и проверку ввода. Таким образом вы автоматически поймаете проблему.

Все основные типы должны иметь имена собственные! Итак, я представил typedef uint_type. Компилятор также узнает уже во время компиляции, является ли ввод 60085147514 действительным или нет (хотя теперь он также отклоняется во время выполнения). Если компилятор предупреждает, вам нужно использовать более крупный целочисленный тип; однако unsigned long достаточно на всех распространенных 64-битных платформах (но не на обычных 32-битных платформах). Если вам нужны более крупные целочисленные типы, то теперь нужно изменить только одно место.

Ваш алгоритм ужасно неэффективен! Все, что нужно, - это разделить число на все найденные множители (как можно дольше), и вы гарантированно встретите только простые числа, поэтому нет необходимости проверять это. А также нужно учитывать только множители до квадратного корня из входных данных. Все это требует некоторой логики, чтобы обдумать - посмотрите код.

Тогда ваш код нарушает принцип локальности: объявляйте свои переменные там, где они нужны, а не где-то еще. Вы также включили заголовки, отличные от C ++, которые к тому же не нужны. Использование директив using просто запутывает код: вы больше не видите, откуда берутся компоненты; и в них нет нужды! Я также ввел анонимное пространство имен для более заметных определений.

Наконец, я использую более компактный стиль кодирования (отступ двумя пробелами, скобки в одной строке, по возможности избегая скобок. Подумайте об этом: таким образом вы можете увидеть гораздо больше с одного взгляда, а немного потренировав его. также легче читать.

При компиляции, как показано, компилятор предупреждает о том, что наибольший_фактор, возможно, используется undefined. Это не так, и я решил считать это предупреждение пустым.

Program LargestPrimeFactor.cpp:
// Compile with
// g++ -O3 -Wall -std=c++98 -pedantic -o LargestPrimeFactor LargestPrimeFactor.cpp

#include <string>
#include <iostream>

namespace {
  const std::string program_name = "LargestPrimeFactor";
  const std::string error_output = "ERROR[" + program_name + "]: ";
  const std::string version_number = "0.1";

  enum ErrorCodes { reading_error = 1, range_error = 2 };
  typedef unsigned long uint_type;
  const uint_type example = 600851475143; // compile-time warnings will show
  // whether uint_type is sufficient
}

int main() {

  uint_type number;
  std::cout << "Please enter a number to have its largest prime factor found:"
   << std::endl;
  std::cin >> number;
  if (not std::cin) {
    std::cerr << error_output << "Number not of the required unsigned integer"
     " type.\n";
    return reading_error;
  }
  if (number <= 1) {
    std::cerr << error_output << "Number " << number << " has no largest prime"
     " factor.\n";
    return range_error;
  }
  const uint_type input = number;

  uint_type largest_factor;
  for (uint_type factor = 2; factor <= number/factor; ++factor)
    if (number % factor == 0) {
      largest_factor = factor;
      do number /= factor; while (number % factor == 0);
    }
  if (number != 1) largest_factor = number;

  std::cout << "The largest prime factor of " << input << " is " << largest_factor
   << ".\n";
}
person Oliver Kullmann    schedule 15.08.2011

И предложить исправление. В зависимости от вашего компилятора вы можете попробовать unsigned long и посмотреть, сможет ли он вместить ваш ответ. Попробуйте написать в cout и посмотрите, содержит ли переменная ожидаемое вами значение.

С другой стороны, если вы пытаетесь найти наибольший фактор, не будет ли более эффективным обратный отсчет от максимально возможного фактора?

person Kenneth    schedule 15.08.2011

Вы можете объявить свою переменную num как long long int.

long long int num;

Это позволит избежать всех типов переполнений, возникающих в вашем коде!

person Harsh Vasoya    schedule 29.11.2017