tatarrr 0 / 0 / 0 Регистрация: 14.02.2013 Сообщений: 108 |
||||
1 |
||||
Как вывести все делители числа25.06.2014, 13:24. Показов 26283. Ответов 17 Метки нет (Все метки)
Вписываем число, должны быть выведены все его делители. Я написал:
Я написал, но проблема в том, что это не совсем эффективно. То есть если число i делится на 2, то нет смысла проверять(как в моем методе) i/2, то есть допустим если число 12 делится на 2, то нет смысла проверять число 6, а надо сразу его вывести. Как это сделать?
0 |
31 / 30 / 13 Регистрация: 15.02.2014 Сообщений: 157 |
|
25.06.2014, 13:30 |
2 |
tatarrr, Мне кажется ваш способ наиболее эффективен. Только если с проверками и хранением данных о числах, которые уже имеются, можно избавиться от вашей проблемы
1 |
0 / 0 / 0 Регистрация: 14.02.2013 Сообщений: 108 |
|
25.06.2014, 13:33 [ТС] |
3 |
fast1kkk
0 |
31 / 30 / 13 Регистрация: 15.02.2014 Сообщений: 157 |
|
25.06.2014, 13:36 |
4 |
tatarrr, Можете показать ваши способы
0 |
Lexeq 1147 / 739 / 483 Регистрация: 21.01.2014 Сообщений: 1,903 |
||||
25.06.2014, 13:51 |
5 |
|||
Так как после i/2 результат будет лежать в пределах от 1 до 2, то нет смысла искать там целочисленные делители. Вообще, вроде бы нужно искать до sqrt(i), но я обычно делаю до i/2, ибо не силен в математике
1 |
993 / 891 / 354 Регистрация: 24.03.2014 Сообщений: 2,381 Записей в блоге: 2 |
|
25.06.2014, 13:55 |
6 |
И вот это стоит почитать, пожалуй…
2 |
sk007 Life Builder 532 / 496 / 374 Регистрация: 12.01.2011 Сообщений: 1,753 |
||||
25.06.2014, 14:16 |
7 |
|||
если число 12 делится на 2, то нет смысла проверять число 6, а надо сразу его вывести. Как это сделать? может break; поставить
1 |
Sergio Leone 2509 / 1130 / 582 Регистрация: 07.06.2014 Сообщений: 3,286 |
||||
25.06.2014, 14:40 |
8 |
|||
Может ваш преподаватель ожидал увидеть такой код:
он выводит все делители числа, только в неотсортированном виде.
1 |
tatarrr 0 / 0 / 0 Регистрация: 14.02.2013 Сообщений: 108 |
||||||||
25.06.2014, 17:01 [ТС] |
9 |
|||||||
Sergio Leone
Этот код пишу, чтобы не было такого казуса, как при числе 9, выводится число 3 два раза
0 |
Psilon Master of Orion 6094 / 4950 / 905 Регистрация: 10.07.2011 Сообщений: 14,522 Записей в блоге: 5 |
||||
25.06.2014, 17:11 |
10 |
|||
tatarrr, просто правая граница включительно должна быть:
и выбирайте для циклом переменные i,j или k. Другие буквы лучше не использовать.
0 |
2509 / 1130 / 582 Регистрация: 07.06.2014 Сообщений: 3,286 |
|
25.06.2014, 19:26 |
11 |
tatarrr, просто правая граница включительно должна быть: сейчас нет возможности проверить код.
0 |
Psilon Master of Orion 6094 / 4950 / 905 Регистрация: 10.07.2011 Сообщений: 14,522 Записей в блоге: 5 |
||||
25.06.2014, 19:32 |
12 |
|||
Sergio Leone, это простое число. Этот код возвращает все делители. Если нужно в конце и само число вывести, в конце можно просто так и сделатЬ:
0 |
2509 / 1130 / 582 Регистрация: 07.06.2014 Сообщений: 3,286 |
|
25.06.2014, 21:20 |
13 |
да я вам о другом толкую. А куда делись делители А мой код с выводом ПАРЫ делителей выводил ВСЕ делители числа, как и требуется в задаче! Нужно только не выводить пару, когда число N является квадратом натурального числа. Добавлено через 2 минуты
Я написал кстати программу исходя из собственных доводов, вот код, как думаете, оценит? О, точно так. Я именно такое и предлагал. Отпишитесь после сдачи о результатах, плиз.
0 |
Master of Orion 6094 / 4950 / 905 Регистрация: 10.07.2011 Сообщений: 14,522 Записей в блоге: 5 |
|
25.06.2014, 22:32 |
14 |
Sergio Leone, тогда берете ваш первый код и это будет самый быстрый вариант. Быстрее не бывает. Что еще хотите?..
1 |
2509 / 1130 / 582 Регистрация: 07.06.2014 Сообщений: 3,286 |
|
25.06.2014, 22:34 |
15 |
Psilon, дык, вся интрига в том, чего преподаватель добивается от автора темы. я верю в то, что результат с i*i<=n препода полностью удовлетворит!
0 |
Psilon Master of Orion 6094 / 4950 / 905 Регистрация: 10.07.2011 Сообщений: 14,522 Записей в блоге: 5 |
||||
25.06.2014, 22:48 |
16 |
|||
Sergio Leone, может был вопрос про простые делители. Потому что до половины доже не вариант смотреть. Например у числа 6 делители 2 4 6, при этом 4 > 6/2. Добавлено через 2 минуты
То есть если число i делится на 2, то нет смысла проверять(как в моем методе) i/2, то есть допустим если число 12 делится на 2, то нет смысла проверять число 6, а надо сразу его вывести. Как это сделать? то есть предлагается найти, что 2 делитель, а после этого
но это бред же. Ни о каком ускорении тут речь идти не может. Добавлено через 42 секунды
0 |
1147 / 739 / 483 Регистрация: 21.01.2014 Сообщений: 1,903 |
|
26.06.2014, 00:00 |
17 |
Потому что до половины доже не вариант смотреть. Например у числа 6 делители 2 4 6, при этом 4 > 6/2. 4? 6/4 = 1.5
1 |
Master of Orion 6094 / 4950 / 905 Регистрация: 10.07.2011 Сообщений: 14,522 Записей в блоге: 5 |
|
26.06.2014, 13:04 |
18 |
Lexeq, да, туплю
0 |
Формулировка задачи:
Вписываем число, должны быть выведены все его делители. Я написал:
Console.Write("Введи число "); int i = int.Parse(Console.ReadLine()); for (int a = 1; a <= i; a++) { if (i % a == 0) Console.Write("{0} ", a); }
Я написал, но проблема в том, что это не совсем эффективно. То есть если число i делится на 2, то нет смысла проверять(как в моем методе) i/2, то есть допустим если число 12 делится на 2, то нет смысла проверять число 6, а надо сразу его вывести. Как это сделать?
Код к задаче: «Как вывести все делители числа»
textual
for (int i = 1; i * i <= n; i++) { if (n % i == 0) Console.WriteLine(i); } Console.WriteLine(n);
Полезно ли:
9 голосов , оценка 4.000 из 5
I saw it would be better if I post an answer instead of using comments.
For your IsPrime
method, I see that you’ve covered most conditions, but you forgot to cover 0, 1, and -n cases, which you can just do with a small change on this line :
if (n % 2 == 0) return false;
to
if (n < 2 || n % 2 == 0) return false;
suggested :
public static bool IsPrime(int n)
{
if(n == 2) { return true; }
if (n < 2 || (n % 2 == 0)) { return false; }
for (int x = 3; x * x <= n; x += 2)
{
if (n % x == 0) { return false; }
}
return true;
}
For GetDivisors
. I assume that you excluded 1
and n
from the results, since it’s already known that every natural number is divisible by 1 and itself, which is fine if you intended to use this code personally, but it is uncommon to do that, and it might even conflict with other developers code, as you don’t want to assume everybody knows that! so it must be included to make the code more usable for others, and you must always consider what is common use, and what is not.
The technique in @gazoh answer is a really good one, and I would take it to the next level, but I have to note out that Sort
and ToArray
are expensive operations as I’ve mentioned in the comments. And I would avoid using them directly.
I’ve updated this method to :
private static IEnumerable<int> GetDivisors(int n)
{
if (n <= 0) { yield return default; }
int iterator = (int)Math.Sqrt(n);
for (int i = 1; i <= iterator; i++)
{
if (n % i == 0)
{
yield return i;
if (i != n / i) { yield return n / i; }
}
}
}
public static IEnumerable<int> GetDivisors(int n, bool AscendingOrder = false)
{
return !AscendingOrder ? GetDivisors(n) : GetDivisors(n).OrderBy(x => x);
}
I’ve used IEnumerable<int>
to open more acceptable collections types rather than just sticking with an array. The overload is just to have an option to order the data, while the default is unordered
data. This would make it optional, which would depend on usage, if you prefer performance over order, or order over performance. Then you can convert it to list or array or any collection.
For performance differences, I’ve used BenchmarkDotNet
to test and compare this method performance and here is the results.
Test 1 using GetDivisors(2095133040)
| Method | Mean | Error | StdDev |
|------------------- |---------------------:|--------------------:|--------------------:|
| Original | 5,907,229,864.000 ns | 116,153,274.6298 ns | 155,061,285.3568 ns |
| ByGazoh | 169,411.783 ns | 2,805.6563 ns | 2,487.1413 ns |
| IEnumerable<int> | 6.637 ns | 0.1896 ns | 0.2107 ns |
| OrderBy | 17.514 ns | 0.3013 ns | 0.2516 ns |
| ToArray | 151,408.141 ns | 2,906.1875 ns | 2,854.2648 ns |
| ToList | 363,424.079 ns | 5,318.8335 ns | 4,975.2401 ns |
| ToArray + OrderBy | 154,249.309 ns | 2,370.8673 ns | 2,101.7121 ns |
| ToList + OrderBy | 356,705.127 ns | 6,002.7773 ns | 5,321.3057 ns |
Test 2 using GetDivisors(1600)
| Method | Mean | Error | StdDev |
|------------------- |-------------:|-----------:|-----------:|
| Original | 4,804.474 ns | 93.0708 ns | 91.4080 ns |
| ByGazoh | 515.822 ns | 7.6545 ns | 7.1601 ns |
| IEnumerable<int> | 6.391 ns | 0.0966 ns | 0.0904 ns |
| OrderBy | 16.783 ns | 0.2839 ns | 0.2517 ns |
| ToArray | 422.570 ns | 6.3368 ns | 5.9274 ns |
| ToList | 463.575 ns | 8.0975 ns | 7.5744 ns |
| ToArray + OrderBy | 1,662.728 ns | 26.8204 ns | 25.0878 ns |
| ToList + OrderBy | 1,634.595 ns | 30.9492 ns | 28.9499 ns |
ns = nano-second;
Where
OrderBy
=Divisors.GetDivisors(n).OrderBy(x=>x);
ToArray
=Divisors.GetDivisors(n).ToArray();
ToList
=Divisors.GetDivisors(n).ToList();
ToArray + OrderBy
=Divisors.GetDivisors(n).OrderBy(x=>x).ToArray();
ToList + OrderBy
=Divisors.GetDivisors(n).OrderBy(x=>x).ToList();
Lastly, regarding your tests, I suggest you test each scenario separately.
Example :
[TestMethod]
public void GetDivisors_15_IsEqual()
{
Assert.AreEqual(new int[] { 3, 5 }, Divisors.Divisors(15));
}
[TestMethod]
public void GetDivisors_16_IsEqual()
{
Assert.AreEqual(new int[] { 2, 4, 8 }, Divisors.Divisors(16));
}
[TestMethod]
public void GetDivisors_253_IsEqual()
{
Assert.AreEqual(new int[] { 11, 23 }, Divisors.Divisors(253));
}
[TestMethod]
public void GetDivisors_24_IsEqual()
{
Assert.AreEqual(new int[] { 2, 3, 4, 6, 8, 12 }, Divisors.Divisors(24));
}
the reason is simple, if you create a separate test for each scenario you have, it’ll be easy to determine which part of your code needs adjustments, and it would make things easier for improving your code (say you want to simplify it without breaking the code). Also, it would be more easier to read and follow, and could give you a better view on the requirements, and the validation process of it.
If you don’t detailed your tests, in smaller projects you might not have any issues, but in big projects, it’ll be a pain in the neck.
I hope this would be useful.
Практикуюсь на Codewars. Написал метод поиска делителей числа. Он проходитит все тесты, кроме Performance Random Test. Получил System.OutOfMemoryException. Что с этим можно сделать? Заранее, спасибо!
public static int[] Divisors(int n)
{
int N = 0;
int[] divisors = new int[n];
for (int i = 2; i < n; i++)
{
if (n % i == 0)
{
divisors[i] = i;
N++;
}
}
int[] ar = new int[N];
int j = 0;
for (int i = 0; i < divisors.Length; i++)
{
if (divisors[i] != 0)
{
ar[j] = divisors[i];
j++;
}
else if (ar.Length == 0)
{
return null;
}
}
return ar;
}
задан 9 фев 2021 в 11:39
5
List<int>
– лучше решение, когда вы не знаете, сколько будет элементов в коллекции.- Число не может делиться на что-то большее, чем половина этого числа (верно?), следовательно перебор уже можно вести только до
n / 2
- Еще круче, если перебор проводить только до квадратного корня числа, при этом добавляя и делитель и частное, так как от перестановки множителей местами произведение не меняется.
Но я думаю и то что я написал, можно еще улучшить. Это так, наивная реализация:
public static int[] Divisors(int n)
{
List<int> divisors = new List<int>();
for (int i = 2; i * i <= n; i++)
{
if (n % i == 0)
{
divisors.Add(i);
if (i * i != n)
divisors.Add(n / i);
}
}
divisors.Sort(); // это для красивого вывода, но можно убрать в пользу производительности
return divisors.ToArray();
}
Еще можно не делать .ToArray()
, а сделать вот так
public static List<int> Divisors(int n)
{
//...
return divisors;
}
Но это зависит от того, обязательное у вас условие вернуть именно массив, или просто так получилось.
ответ дан 9 фев 2021 в 12:01
aepot♦aepot
45k5 золотых знаков22 серебряных знака50 бронзовых знаков
5
Как найти количество делителей числа.
Например число
20 -> 1 2 4 5 10 20
1 -> 1 = 1
2 -> 1, 2 = 2
4 -> 1, 2, 4 = 3
5 -> 1, 2 = 2
10 -> 1, 2, 5, 10 = 4
20 -> 1, 2, 4, 5, 10, 10 = 6
1 + 2 + 3 + 2 + 4 + 6 = 18
Harry
144k10 золотых знаков80 серебряных знаков179 бронзовых знаков
задан 3 сен ’16 в 5:31
Откровенно говоря, ничего умнее, чем перебор простых делителей числа до sqrt(N)
не вижу. Ну, а потом – перебор сочетаний этих простых делителей в составные делители. Понятно, что при нахождении простого делителя делим число на него и начинаем все сначала. И не менее понятно, что количество всех сочетаний (== количество делителей) есть просто произведение всех степеней простых делителей, увеличенные на 1. Ну, например, 360 = 2^3 * 3^2 * 5^1
, так что число делителей (3+1)*(2+1)*(1+1)=24
.
Если числа небольшие – можно просто перебор всех подряд делителей до sqrt(N)
, с учетом, что для каждого такого делителя, отличного от 1, есть соответствующий делитель с обратной стороны от sqrt(N)
.
Код нужен? 🙂
Update: пример – вывод количества всех делителей (включая 1 и само число)
ответ дан 3 сен ’16 в 7:21
HarryHarry
144k10 золотых знаков80 серебряных знаков179 бронзовых знаков
Можно, найти алгоритм и немного получше, чем перебор простых делителей числа до sqrt(N)
.
Обратим внимание на тот факт, что любое число, можно представить как произведение простых множителей, таким образом если мы нашли один простой делитель, то далее нам не надо искать делители N
, а надо искать делители от частного N/x
, где х
– наш простой делитель.
Например так. (Извиняюсь за C#)
uint[] simpl_arr = //массив заполненный простыми числами
public List<int> GetSimpleDividors(uint number)
{
List<int> result = new List<int>();
uint s = Convert.ToUInt32(Math.Ceiling(Math.Sqrt(number)));
for ( int i = 0 ; simple_arr[i] < s ; i++ )
{
if (number % simple_arr[i] == 0)
{
result.Add(simple_arr[i]);
uint quotient = number / simple_arr[i];
var tmp = GetSimpleDividors(quotent);
if (tmp.Count > 0)
{
result.AddRange(tmp);
}
else
{
result.Add(quotent);
}
break;
}
}
return result;
}
ответ дан 3 сен ’16 в 12:27
MirdinMirdin
5,7421 золотой знак18 серебряных знаков29 бронзовых знаков
Можно в цикле через алгоритм Евклида считать до деления на 0.
До конца цикла проверять результат деления: если остаток от деления равен 0, то прибавить 1 к счётчику.
В счётчике считаем количество делителей.
ответ дан 5 июн ’18 в 21:20
XalionXalion
361 бронзовый знак