Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Разбитие целого числа на цифры.


Автор: zaksys 5.2.2009, 18:08
У меня есть такая задача. Есть целое число, которое мы вводим с клавиатуры. И необходимо узнать сколько в этом числе нечетных и четных цифр. 
Примерно был написан такой код.
Код

using System;
using System.Collections.Generic;
using System.Text;

namespace Лабороторная__1
{
    class Program
    {
        static void Main(string[] args)
        {
            string buf;
            Console.WriteLine("Ввидите целое число");
            buf = Console.ReadLine();
            int i = Convert.ToInt32(buf);
            int a = 0;
            int b = 0;
            int c = 0;
            while (i='')
            {
            i= Console.Read();
            c = i % 2;
            if(c==0)
            {
            a++;         
            }
            else
            {
            b++;
            };
            };
            Console.WriteLine("Количество четных цифр"+a+"в числе" + i);
            Console.WriteLine("Количество не четных цифр"+b+"в числе"+i);
            Console.ReadLine();        
        }
    }
}

Подскажите, где здесь ошибка пожалуйста.

Автор: diadiavova 5.2.2009, 18:45
Код

        static void Main(string[] args)
        {
            string buf;
            Console.WriteLine("Введите целое число");
            buf = Console.ReadLine();
            int i = int.Parse(buf);
            int a = 0;
            int b = 0;
            System.Collections.IEnumerator en = buf.GetEnumerator();
            while (en.MoveNext())
            {
                int cur = int.Parse(en.Current.ToString());
                if (cur % 2 == 0)
                {
                    a++;
                }
                else
                {
                    b++;
                };
            };
            Console.WriteLine("Количество четных цифр " + a.ToString() + " в числе " + i.ToString());
            Console.WriteLine("Количество не четных цифр " + b.ToString() + " в числе " + i.ToString());
            Console.ReadLine();
        }


Правда, в дополнение к этому ещё неплохо было бы проверить корректность введённых данных.

Автор: zaksys 5.2.2009, 19:39
Код

System.Collections.IEnumerator en = buf.GetEnumerator();
while (en.MoveNext())

А можно объснить откуда это взялось, и что можно по этой теме почитать?

Автор: diadiavova 5.2.2009, 19:44
Почитать попробуй официальную документацию по этому интерфейсу. Перечислитель просто перебирает буквы в строке. Метод MoveNext переводит его на следующую букву и есле она ещё есть, то возвращает true, в противном случае(если строка кончилась) цикл обрывается. Свойство Current возвращает текущую букву.

Автор: QryStaL 5.2.2009, 22:25
Цитата(zaksys @  5.2.2009,  19:39 Найти цитируемый пост)
А можно объснить откуда это взялось, и что можно по этой теме почитать?

Этот код эквивалентен следующему

Код

foreach (Char c in buf)
{
    int cur = int.Parse(c.ToString());
    if (cur % 2 == 0)
    {
        a++;
    }
    else
    {
        b++;
    }
}


Добавлено через 1 минуту и 7 секунд
http://dofactory.com/patterns/PatternIterator.aspx

Автор: zaksys 6.2.2009, 12:26
А есть какие-нибудь рускоязычные источники?

Автор: QryStaL 6.2.2009, 13:00
http://www.rsdn.ru/res/book/oo/design_patterns.xml

Шаблон Итератор

Автор: PashaPash 6.2.2009, 16:59
diadiavovaQryStaL, я просто в шоке. Считать четные/нечетные цифры преобразованием числа в строку - это позор. Оба примера падают даже на -1 smile

Добавлено через 5 минут и 9 секунд
Код

        static void Main(string[] args)
        {
            string buf;
            Console.WriteLine("Введите целое число: ");
            buf = Console.ReadLine();
            int i = int.Parse(buf);
            int a = 0;
            int b = 0;

            do
            {
                int rem;
                i = Math.DivRem(i, 10, out rem);
                if (rem % 2 == 0)
                {
                    a++;
                }
                else
                {
                    b++;
                }
            }
            while (i != 0);


            Console.WriteLine("Количество четных цифр: " + a.ToString());
            Console.WriteLine("Количество нечетных цифр: " + b.ToString());
            Console.ReadLine();
        }

шаблон "Остаток от деления на 10" (с)

Автор: diadiavova 6.2.2009, 17:14
PashaPash, я тебя ещё больше шокирую. В дополнение к тому позору, о котором ты уже написал, я ещё плюс ко всему не смог найти в своём собственном коде того места, в котором я преобразовывал бы число в строку с вышеозначенной целью. Так что: не сочти за труд - укажи место поточнее. smile 

Автор: PashaPash 6.2.2009, 17:21
Ты работаешь со строковым представлением числа. Выше у тебя уже есть готовое число в виде int. Это как-бы и есть преобразование числа в строку для решения мегазадачи smile Согласись, код с душком получился, да еще и с ручным энумератором. И на отрицательных падает.

Автор: diadiavova 6.2.2009, 17:37
Со строкой я работаю в силу того, что задача состоит в подсчёте цифр(которые как известно являются символами), из-за этого, на мой взгляд их куда более естественно извлекать прямо из строки, чем выполнять математические операции над числом после преобразования. Что до отрицательных чисел и прочих прелестей - это всё можно скорректировать если такое условие будет поставлено, насколько я понимаю, в твоём коде тоже отсутствует проверка корректности введённых данных ( только какое это имеет отношение к задаче?). 
Для проверки чётности я использовал тот же механизм что и ты(а не преобразование в строку). Что касается ручного энумератора, то здесь я, пожалуй, согласен, только вот...недостаток этот исправил QryStaL, но он тебя тоже почему-то шокировал. Я же его использовал для сохранения сходства с первоначальным кодом, для пущей ясности, пропёрся малость - бывает. ....Или ты опять намекаешь, что я про форич не в курсях?

Автор: QryStaL 6.2.2009, 17:45
PashaPash, начнем с того, что я алгоритм вообще никак не комментировал, а просто ответил на вопрос автора про кусок кода (указал на возможность использования конструкции foreach)  smile 

Автор: zaksys 6.2.2009, 18:19
Не понятно о чем тут написано, но все равно спасибо за помощь.  

Автор: PashaPash 6.2.2009, 18:53
QryStaL, да с тобой все понятно smile У тебя в коде только проверки на "-" нет.
Цитата(diadiavova @  6.2.2009,  17:37 Найти цитируемый пост)
Со строкой я работаю в силу того, что задача состоит в подсчёте цифр(которые как известно являются символами)

Да, только для опередления цифр, стоящих в десятичной записи числа есть готовый древний алгоритм с делением. Код пишется для машины, в которой числа представлены не строковыми литералами. И преобразование их в строки равносильно проверке val==true кодом типа if (val.ToString().Length == 4).
Твой код считает количество четных одноразраядных чисел в введенной строке. Самого понятия "введенного числа" в нем нет. 
Как-то видет - для передачи массива чисел по сети их преобразовывали в строчку. И аргументировали - send(char*), значит надо передать строку. ;)
Цитата(diadiavova @  6.2.2009,  17:37 Найти цитируемый пост)
Что до отрицательных чисел и прочих прелестей - это всё можно скорректировать если такое условие будет поставлено, насколько я понимаю, в твоём коде тоже отсутствует проверка корректности введённых данных ( только какое это имеет отношение к задаче?).

В условии написано - целых чисел. Отрицательные натуральные - это целые. Условие уже поставлено, так что отрицательные числа имеют к задаче вполне конкретное отношение smile А про проверку корректности в условии ничего нет.

Автор: diadiavova 6.2.2009, 20:02
zaksys, спор идёт о способе решения твоей задачи. В варианте, предложенном мной, строка просто перебирается посимвольно, и каждый символ проверяется на предмет соответствия условию. В варианте, предлагаемом PashaPash строку сначала надо преобразовать в число, а потом выдирать из этого числа отдельные цифры, используя простой(по его мнению) алгоритм, состоящий в том, что число в каждой итерации цикла делится на 10, остаток деления проверяется на предмет деления на 2 а с результатом деления эта операция повторяется до тех пор, пока он не иссякнет (я ничего не напутал?).
PashaPash, в приведённом примере исходными данными является строка, так что: никто ничего не преобразовывал. Преобразовывать входную строку в число - действительно не надо было(переменная i там лишняя).

Цитата(PashaPash @  6.2.2009,  18:53 Найти цитируемый пост)
А про проверку корректности в условии ничего нет.

Ну если ты так строго подходишь к этому учебному примеру и хочешь сделать из него настоящую программу, то "защиту от дурака" предусмотреть надо, несмотря на отсутствие такого требования в постановке задачи.

Автор: PashaPash 6.2.2009, 20:14
Цитата(diadiavova @  6.2.2009,  20:02 Найти цитируемый пост)
PashaPash, в приведённом примере исходными данными является строка, так что: никто ничего не преобразовывал. Преобразовывать входную строку в число - действительно не надо было(переменная i там лишняя).

В приведенном условии встречаются слова "целое число". Скорее, преобразовывать каждый символ отдельно в число не надо было. А просто взять и написать стандартный алгоритм.
Цитата(diadiavova @  6.2.2009,  20:02 Найти цитируемый пост)
Ну если ты так строго подходишь к этому учебному примеру и хочешь сделать из него настоящую программу, то "защиту от дурака" предусмотреть надо, несмотря на отсутствие такого требования в постановке задачи.

Вот такой я строгий и злой smile Требование на поддержку отрицательных чисел в постановке задачи есть. Твой код на них падает. Я виноват? smile

Автор: diadiavova 6.2.2009, 20:22
То, что мой код "падает" на отрицательных числах -  всего навсего небольшой недочёт, который исправляется элементарно(уверен: ты и сам это понимаешь). Ты так на этом зацикливаешься, что создаётся впечатление, как будто попытка исправить этот недочёт способна убить алгоритм. В любом случае: перебрать строку - проще и дешевле, чем выполнять арифметические операции над числом(полученным из этой же строки) для получения того же результата.

Автор: PashaPash 6.2.2009, 20:49
Цитата(diadiavova @  6.2.2009,  20:22 Найти цитируемый пост)
В любом случае: перебрать строку - проще и дешевле, чем выполнять арифметические операции над числом(полученным из этой же строки) для получения того же результата.

Проще и дешевле??? С каких это пор преобразование строки в число (для каждого символа) стало проще и дешевле деления на 10 - одной процессорной инструкции? smile) Мой код вызывает Int32.Parse один раз. Твой - один раз для каждой цифры - офигенно дешевле smile Предлагаешь ввести проверки true.ToString().Length == 4 в качестве оптимизации? smile)
Цитата(diadiavova @  6.2.2009,  20:22 Найти цитируемый пост)
То, что мой код "падает" на отрицательных числах -  всего навсего небольшой недочёт, который исправляется элементарно(уверен: ты и сам это понимаешь). 

Это большой недочет. Попытка исправления его подвинет алгортм на один шаг в сторону спагетти. Уверен, ты понимаешь сколько стоит выловить такой "недочет" в системе средних размеров. Так же уверен, что ты понимаешь что на самом деле для введения хоть какой-нибудь валидации ввода тебе придется обработать минимум 3 крайних случая вручную, и при этом повторить функционал стандартного Int32.Parse(). Хотя, после фразы что операция со строками дешевле деления - я уже не уверен smile

Автор: zaksys 6.2.2009, 21:06
Я сначала думал перебрать преобразованное число по цифрам, и их сравнивать. Просто не знал как выделить из полученного числа цифры, чтоб потом просто проверить четные они не четные.

Автор: diadiavova 6.2.2009, 21:11
zaksys, ну тогда, вариант PashaPash для тебя.

PashaPash, Сомневаюсь, что деление, с нахождением остатка - более дешёвая процедура, чем парсинг строки из одного символа. Хотя: спорить об этом умозрительно нет никакого смысла, а проверять на практике, я думаю не хочется ни тебе ни мне. 
Цитата(PashaPash @  6.2.2009,  20:49 Найти цитируемый пост)
Уверен, ты понимаешь сколько стоит выловить такой "недочет" в системе средних размеров.

Ты хочешь сказать, что проверка наличия минуса в строке - настолько дорогое удовольствие, что слабой машине с этой сверзадачей не справиться?
Цитата(PashaPash @  6.2.2009,  20:49 Найти цитируемый пост)
Так же уверен, что ты понимаешь что на самом деле для введения хоть какой-нибудь валидации ввода тебе придется обработать минимум 3 крайних случая вручную, и при этом повторить функционал стандартного Int32.Parse(). 

Проверка введённых данных к теме имеет косвенное отношение, и если её вводить, то и расклад другой будет.

Автор: PashaPash 6.2.2009, 21:23
Цитата(diadiavova @  6.2.2009,  21:11 Найти цитируемый пост)
PashaPash, Сомневаюсь, что деление, с нахождением остатка - более дешёвая процедура, чем парсинг строки из одного символа. Хотя: спорить об этом умозрительно нет никакого смысла, а проверять на практике, я думаю не хочется ни тебе ни мне. 

Деление с нахождением остатка - ровно одна инструкция процессора. Парсинг строки число в C# - это сложная операция, у четом текущей локали, кучи левых проверок типа на всякие там leading/traling space. Сложнее на пару порядков - возьми отладчик и убедись.
Цитата(diadiavova @  6.2.2009,  21:11 Найти цитируемый пост)

Ты хочешь сказать, что проверка наличия минуса в строке - настолько дорогое удовольствие, что слабой машине с этой сверзадачей не справиться?

Я имею в виду что сам поиск такой ошибки будет достаточно трудоемкой операцией. Если даже 5 строчек не работают точно по однострочной спеке, то как можно доверить тебе проект? smile

Автор: diadiavova 6.2.2009, 21:35
Цитата(PashaPash @  6.2.2009,  21:23 Найти цитируемый пост)
Я имею в виду что сам поиск такой ошибки будет достаточно трудоемкой операцией. 

Я имею в виду не поиск ошибки, а то, что код надо просто чуть-чуть подправить.

Цитата(PashaPash @  6.2.2009,  21:23 Найти цитируемый пост)
Если даже 5 строчек не работают точно по однострочной спеке, то как можно доверить тебе проект?

На сколько я понимаю, я к тебе на работу не устраиваюсь smile 

Автор: PashaPash 6.2.2009, 21:44
diadiavova, да просто пятница, пиво закончилось, а на форму тишина....

Автор: diadiavova 6.2.2009, 21:48
Ты на форум VB.Net зайди, тогда узнаешь, что такое тишина.

Автор: THandle 7.2.2009, 21:41
Модератор: Давайте вернёмся к теме обсуждения.

Тишину и прочее можно обсудить во http://forum.vingrad.ru/forum/Flame.html ;)

Автор: diadiavova 8.2.2009, 16:50
Цитата(diadiavova @  6.2.2009,  20:22 Найти цитируемый пост)
В любом случае: перебрать строку - проще и дешевле, чем выполнять арифметические операции над числом(полученным из этой же строки) для получения того же результата.

Я так понимаю, что неодобрительную оценку я получил именно за это утверждение. В связи с этим, я немного подправил алгоритм(от преобразования строки в число отказался вовсе и заменил его свитчкейсом), решил проблему отрицательных чисел. 
Программа содержит текстовый файл, состоящий из 100000 строк, на каждой из которых записано целое число в интервале от -1000000 до 1000000 . Файл считывается построчно, и каждая строка передаётся на обработку первому алгоритму(моему), после чего аналогичные действия производятся со вторым алгоритмом. Время, затраченное на обработку выводится на экран.

Файл сгенерирован рэндомно, метод при помощи которого это было сделано, представлен.

Автор: zaksys 8.2.2009, 18:01
А как решить проблему отрицательных чисел?(Чтоб их можно было безболезнено считывать, также как и положительные).


 ! 
THandle
Кнопка Report используется только по следующим правилам:

Цитата

Эта форма должна быть использована ТОЛЬКО для доклада о НАРУШЕНИИ ПРАВИЛ ФОРУМА в сообщении и ни в коем случае не как средство общения и связи.


В следующий раз за не целевое использование будет выдано предупреждение.

Автор: PashaPash 8.2.2009, 19:25
Цитата(zaksys @  8.2.2009,  18:01 Найти цитируемый пост)
А как решить проблему отрицательных чисел?(Чтоб их можно было безболезнено считывать, также как и положительные).

Отмотай на мой пост на прошлой странице, там готовый код.

Добавлено через 6 минут и 18 секунд
Цитата(diadiavova @  8.2.2009,  16:50 Найти цитируемый пост)
Я так понимаю, что неодобрительную оценку я получил именно за это утверждение. В связи с этим, я немного подправил алгоритм(от преобразования строки в число отказался вовсе и заменил его свитчкейсом), решил проблему отрицательных чисел. 

Не за это утверждение, а за общую кривизну решения детской задачи.

Автор: diadiavova 8.2.2009, 20:55
А по поводу результатов теста будут комментарии?

Автор: PashaPash 8.2.2009, 21:11
diadiavova, замечательный тест, вот только студии под рукой нет. А так - почему ты передаешь string buf? В условии ж сказано - целое число. Поменяй - получишь обратный результат smile
И зачем ручная работа с энумератором? В чем вообще цель? Доказать что можно проверять на четность свитчем?
Твой вариант препод завернет с фразой "а почему вы в число не преобразовываете как я вам показывал" smile почти 100% smile

Автор: diadiavova 8.2.2009, 21:18
Не надо передёргивать. Мы обсуждали вопрос о том, что проглотит меньше ресурсов. Тест был исключительно на эту тему. Первоначально ты мне доказывал, что преобразование в число "дешевле", теперь - откуда ни возьмись, нарисовался препод. 
"string buf" я передаю только потому, что с самого начала так сделал. В этом и состояла моя идея. И студия тут ни при чём - там есть бинарник.

Автор: Veon 8.2.2009, 22:18
Ужасный тест smile
Для единичного случая намного лучше подходи то, что написал PashaPash. Если уж ты хочешь обрабатывать большое кол-во строк, то есть намного лучше способы чем этот case smile

Кое-чего поправил, чтобы более обьективно было

Убрал
Код

while (!sr.EndOfStream)
{}            {

Лучше тест проводить на готовом массиве строк.

Твоя прога с исправлениями (3-й способ работает только для положительных, можно его выкинуть)
Код

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
namespace AlgTest
{
    class Program
    {
        private static bool[] chars = new bool[255];
        private static int[] chars1 = new int[255];
        private static int[] chars2 = new int[255];

        static void Main(string[] args)
        {
            string fn = "source.txt";
            StreamReader sr = new StreamReader(fn);

            string[] arr = sr.ReadToEnd().Split(new string[] { "\r\n" }, StringSplitOptions.None);
            sr.Close();

            DateTime startAlg1 = DateTime.Now;
            foreach (string value in arr)
            {
                Alg1(value);
            }
            DateTime endAlg1 = DateTime.Now;

            DateTime startAlg2 = DateTime.Now;
            foreach (string value in arr)
            {
                Alg2(value);
            }
            DateTime endAlg2 = DateTime.Now;

            //new alg
            chars['1'] = false;
            chars['3'] = false;
            chars['5'] = false;
            chars['7'] = false;
            chars['9'] = false;
            chars['0'] = true;
            chars['2'] = true;
            chars['4'] = true;
            chars['6'] = true;
            chars['8'] = true;

            DateTime startAlg3 = DateTime.Now;
            foreach (string value in arr)
            {
                Alg3(value);
            }
            DateTime endAlg3 = DateTime.Now;

            //new alg2
            chars1['1'] = 100;
            chars1['3'] = 100;
            chars1['5'] = 100;
            chars1['7'] = 100;
            chars1['9'] = 100;
            chars1['0'] = 1;
            chars1['2'] = 1;
            chars1['4'] = 1;
            chars1['6'] = 1;
            chars1['8'] = 1;

            DateTime startAlg4 = DateTime.Now;
            foreach (string value in arr)
            {
                Alg4(value);
            }
            DateTime endAlg4 = DateTime.Now;
            sr.Close();



            TimeSpan a1 = endAlg1.Subtract(startAlg1);
            TimeSpan a2 = endAlg2.Subtract(startAlg2);
            TimeSpan a3 = endAlg3.Subtract(startAlg3);
            TimeSpan a4 = endAlg4.Subtract(startAlg4);

            Console.WriteLine("Время затраченное на выполнение алгоритма без преобразования в число");
            Console.WriteLine(a1.Milliseconds.ToString());
            Console.WriteLine("Время затраченное на выполнение алгоритма с преобразованием в число");
            Console.WriteLine(a2.Milliseconds.ToString());
            Console.WriteLine("Время затраченное на alg3");
            Console.WriteLine(a3.Milliseconds.ToString());
            Console.WriteLine("Время затраченное на alg4");
            Console.WriteLine(a4.Milliseconds.ToString());

            Console.ReadLine();
        }

        static void Alg4(string buf)
        {
            int z = 0;
            int a = 0;
            int b = 0;
            foreach (char q in buf)
            {
                z += chars1[q];
            }
            a = z / 100;
            b = z % 100;
        }

        static void Alg3(string buf)
        {
            int a = 0;
            int b = 0;
            foreach (char q in buf)
            {
                if (chars[q])
                    a++;
                else
                    b++;
            }
        }


        static void Alg1(string buf)
        {
            int a = 0;
            int b = 0;
            System.Collections.IEnumerator en = buf.GetEnumerator();
            while (en.MoveNext())
            {
                char cur = (char)en.Current;
                switch (cur)
                {
                    case '0':
                    case '2':
                    case '4':
                    case '6':
                    case '8':
                        a++;
                        break;
                    case '1':
                    case '3':
                    case '5':
                    case '7':
                    case '9':
                        b++;
                        break;
                }
            };
        }

        static void Alg2(string buf)
        {
            int i = int.Parse(buf);
            int a = 0;
            int b = 0;
            do
            {
                int rem;
                i = Math.DivRem(i, 10, out rem);
                if (rem % 2 == 0)
                {
                    a++;
                }
                else
                {
                    b++;
                }
            }
            while (i != 0);
        }

        static void createFile()
        {
            Random r = new Random();
            string fn = "source.txt";

            List<string> qq = new List<string>();

            for (int i = 0; i < 1000000; i++)
            {
                qq.Add(r.Next(-1000000, 1000000).ToString());
            }
            File.WriteAllText(fn, String.Join("\r\n", qq.ToArray()));
        }
    }
}




Да, еще попробовал как оно работает на 1кк строк, после вызова твоего createFile немного офигел smile Запаришься ждать столько времени с твоими s+=
И проводи тесты лучше в release smile

Зы: мои результаты
Время затраченное на выполнение алгоритма без преобразования в число
196
Время затраченное на выполнение алгоритма с преобразованием в число
227
Время затраченное на alg3
17
Время затраченное на alg4
17

Хотя если в твоем методе с case поправить на
Код

            foreach (char cur in buf)


выдает 14 smile

Автор: diadiavova 9.2.2009, 01:38
Цитата(Veon @  8.2.2009,  22:18 Найти цитируемый пост)
Убрал

while (!sr.EndOfStream)
{}            

Это зря, оно как бы подразумевалось, забивать все данные в память не всегда целесообразно. 

Относительно метода CreateFile делать его идеальным я не собирался, потому, что в программе он не используется, написан на скорую руку, вызван единственный раз. Сделал своё дело и свободен. Оставил я его только для сведения о том, как был сформирован файл.

При замене энумератора форичем код действительно работает быстрее(не знал). 

Твои алгоритмы действительно показывают лучшие результаты.

Тест надо запускать несколько раз, поскольк результаты могут отличаться. Идеальным вариантом было бы прогнать по каждому алгоритму несколько раз и выводить усреднённые значения, хотя...и так всё видно.

Кроме того: в качестве результата выводятся только миллисекунды, но если запустить тест на слабой машине могут и секунды возникнуть , а учтены они не будут(это я так на всякий случай).
вместо a1.Milliseconds.ToString() надо писать a1.ToString().     Это для полноты картины.

В любом случае, в контексте темы, вывод один...

Автор: PashaPash 9.2.2009, 02:17
Цитата(diadiavova @  8.2.2009,  21:18 Найти цитируемый пост)
Не надо передёргивать. Мы обсуждали вопрос о том, что проглотит меньше ресурсов. Тест был исключительно на эту тему. Первоначально ты мне доказывал, что преобразование в число "дешевле", теперь - откуда ни возьмись, нарисовался препод. 

Не надо передергивать. Я сказал про преобразование каждого символа в число vs деление. Прогони свой первоначальный вариант smile Вырезать такой ляп и начать сравнивать - не честно smile
Цитата(diadiavova @  9.2.2009,  01:38 Найти цитируемый пост)
В любом случае, в контексте темы, вывод один... 

Какой?

И, кстати, DateTime+TimeSpan => System.Diagnostics.Stopwatch.

Автор: diadiavova 9.2.2009, 11:24
Цитата(PashaPash @  9.2.2009,  02:17 Найти цитируемый пост)
Не надо передергивать. Я сказал про преобразование каждого символа в число vs деление. Прогони свой первоначальный вариант smile Вырезать такой ляп и начать сравнивать - не честно

Не надо передёргивать: мой первоначальный вариант подвергся критике по совершенно другому поводу. 
Цитата(PashaPash @  6.2.2009,  16:59 Найти цитируемый пост)
Считать четные/нечетные цифры преобразованием числа в строку - это позор.

Далее, после уточнения, что я этого не делаю(здесь ты просто пропёрся, по этому поводу претензий нет - со всеми бывает) ты заявил следующее
Цитата(PashaPash @  6.2.2009,  17:21 Найти цитируемый пост)
Ты работаешь со строковым представлением числа.

И дальнейший спор развивался в контексте вопроса, что в данном случае лучше - преобразование в число или работа со строкой. И кстати: я не понял, ты уже не споришь с тем, что в данном конкретном случае лучше обрабатывать строку непосредственно? smile 

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

               switch (cur)
                {
                    case '0':
                    case '2':
                    case '4':
                    case '6':
                    case '8':
                        a++;
                        break;
                    case '1':
                    case '3':
                    case '5':
                    case '7':
                    case '9':
                        b++;
                        break;
                }


На васике выглядит так

Код

Select Case buf
    Case "0"c," 2"c, "4"c, "6"c, "8"c
        a+=1
    Case "1"c," 3"c, "5"c, "7"c, "9"c
        b+=1
End Select

То бишь  -  2 инструкции кейс вместо 10.

Цитата(PashaPash @  9.2.2009,  02:17 Найти цитируемый пост)
Какой?

По-моему мы говорили о скорости работы алгоритмов.
Цитата(PashaPash @  9.2.2009,  02:17 Найти цитируемый пост)
И, кстати, DateTime+TimeSpan => System.Diagnostics.Stopwatch.

А это ты к чему?


Автор: PashaPash 9.2.2009, 11:42
Цитата(diadiavova @  9.2.2009,  11:24 Найти цитируемый пост)
Не надо передёргивать: мой первоначальный вариант подвергся критике по совершенно другому поводу. 

Цитата(diadiavova @  9.2.2009,  11:24 Найти цитируемый пост)

По-моему мы говорили о скорости работы алгоритмов.

отдельно о скорости, обычно об общем подходе.О скорости:
Цитата(PashaPash @  6.2.2009,  20:49 Найти цитируемый пост)

Проще и дешевле??? С каких это пор преобразование строки в число (для каждого символа) стало проще и дешевле деления на 10 - одной процессорной инструкции? smile)

Вроде бы спор о производительности я утверждал только вот это.
И первоначальный вариант я критиковал именно за "двойное преобразование". Точнее, за цепочку "уже готовый string->int игнорируется"->"возврат к строке"->"ручной энумератор"->"боксинг/анбоксинг"->"преобразование char в string (посимвольное)"->"преобразование string->int (посимвольно)". Видишь тут аж 5 (!) кастов каждого символа? А можно было сделать всего один, и обойтись делением. 
Цитата(diadiavova @  9.2.2009,  11:24 Найти цитируемый пост)
И дальнейший спор развивался в контексте вопроса, что в данном случае лучше - преобразование в число или работа со строкой. И кстати: я не понял, ты уже не споришь с тем, что в данном конкретном случае лучше обрабатывать строку непосредственно? smile 

В данном конкретном случае это явно задача с каких нибудь курсов. И цель ее явно не научить перебирать символы в строке, а научить работать с целыми числами, делить с остатком и проверять четность. Задачи "найти количество символов 0 2 4 6 8 и 1 3 5 7 9" формулируются обычно совсем по-другому.

Мой  вывод - если человека раздразнить - он вылижет совй код smile)

Добавлено через 43 секунды
Цитата(diadiavova @  9.2.2009,  11:24 Найти цитируемый пост)
И, кстати, DateTime+TimeSpan => System.Diagnostics.Stopwatch.

А это ты к чему?

Это класс специально для меряния временем.

Автор: Veon 9.2.2009, 11:46
Ну вообще-то задача звучала так "Есть целое число, которое мы вводим с клавиатуры. И необходимо узнать сколько в этом числе нечетных и четных цифр. "
В стандартном методе PashaPash как раз таки работают с числами, вставить туда TryParse и вообще будет хорошо.
diadiavova же считает в строке количество символов '0', '1'... Проглотит число qqq1aaa?
Цитата(diadiavova @  8.2.2009,  23:38 Найти цитируемый пост)
Твои алгоритмы действительно показывают лучшие результаты.

На моей машине 9 case работают быстрее чем с массивами. Я думал что будет наоборот.
Пример с массивами я приводил только чтобы показать, что есть методы быстрее твоего (ошибся и не привел smile).

А ты занимаешься преждевременной оптимизацией.
Мало того что нет таких сферических прог в которых нужно обрабатывать миллионы строк, так в 1-й раз ты парсил каждую цифру, а во второй использовал Enumerator. Вести спор о ресурсах и скорости вычисления, когда за 10 секунд можно набрасать метод работающий аналогично твоему (не PashaPash), но в 10 раз быстрее smile

Блин, пока писал уже то-же самое ответили smile

Автор: diadiavova 9.2.2009, 12:44
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
отдельно о скорости, обычно об общем подходе.

Для того, чтобы обсуждать общий подход, надо определиться для начала с критериями оценки оновго подхода.
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
string->int игнорируется"

Я скопипастил исходный пример и исправлял его. Учитывая, что я применил другой подход, исправлять надо было более радикально. При дальнейшем обсуждении я написал, что в число преобразовывать вообще н следовало и мы это обсуждали.
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
"возврат к строке"

Возврата не было, я просто проигнорировал преобразованное число, ещё раз повторяю, что если бы я сам писал код с самого начала, то строку вообще не парсил бы.
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
"ручной энумератор"

Здесь согласен(учитывая результаты теста).
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
"преобразование char в string (посимвольное)"

Здесь тоже спорить не буду, хотя твой "праведный гнев" был направлен совсем в другую сторону. 
Возникает интересная ситуация: первоначально ты критикуешь непосредственную работу со строкой, потом, когда выясняется, что критика была неуместной, начинаешь придираться к деталям, возникшим вследствие того, что код писался "не на выставку". 
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
Вроде бы спор о производительности я утверждал только вот это.

Да нет, ещё и вот это как бы имеет отношение к делу
Цитата(PashaPash @  6.2.2009,  20:49 Найти цитируемый пост)
Это большой недочет. Попытка исправления его подвинет алгортм на один шаг в сторону спагетти. Уверен, ты понимаешь сколько стоит выловить такой "недочет" в системе средних размеров.

Напомню: речь шла о "падении на отрицательных". Куда подвинула попытка его исправления мы видели - алгоритм заработал быстрее.
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
В данном конкретном случае это явно задача с каких нибудь курсов. И цель ее явно не научить перебирать символы в строке, а научить работать с целыми числами, делить с остатком и проверять четность. Задачи "найти количество символов 0 2 4 6 8 и 1 3 5 7 9" формулируются обычно совсем по-другому.

Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
В данном конкретном случае это явно задача с каких нибудь курсов. И цель ее явно не научить перебирать символы в строке, а научить работать с целыми числами, делить с остатком и проверять четность. Задачи "найти количество символов 0 2 4 6 8 и 1 3 5 7 9" формулируются обычно совсем по-другому.

Возможно, только
Цитата(PashaPash @  6.2.2009,  18:53 Найти цитируемый пост)
В условии написано - целых чисел. Отрицательные натуральные - это целые. Условие уже поставлено, так что отрицательные числа имеют к задаче вполне конкретное отношение smile А про проверку корректности в условии ничего нет.

Раз ты так уж уповаешь на условия, то давай не будем от них отступать. В условии шла речь о решении конкретной задачи, а не о способе её решения.
Цитата(PashaPash @  9.2.2009,  11:42 Найти цитируемый пост)
Мой  вывод - если человека раздразнить - он вылижет совй код 

Для того, чтобы "вылизать" код надо, как минимум знатькак это сделать. Вся фишка в том, что общую концепцию я не изменил при "вылизывании". Я всё равно обрабатываю строку непосредственно и алгоритм работает быстрее твого smile 

Цитата(Veon @  9.2.2009,  11:46 Найти цитируемый пост)
Ну вообще-то задача звучала так "Есть целое число, которое мы вводим с клавиатуры. И необходимо узнать сколько в этом числе нечетных и четных цифр. "
В стандартном методе PashaPash как раз таки работают с числами, вставить туда TryParse и вообще будет хорошо.
diadiavova же считает в строке количество символов '0', '1'... Проглотит число qqq1aaa?


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

Цитата(Veon @  9.2.2009,  11:46 Найти цитируемый пост)
Мало того что нет таких сферических прог в которых нужно обрабатывать миллионы строк, так в 1-й раз ты парсил каждую цифру, а во второй использовал Enumerator. Вести спор о ресурсах и скорости вычисления, когда за 10 секунд можно набрасать метод работающий аналогично твоему (не PashaPash), но в 10 раз быстрее

В 10 раз - это ты загнул. 

И потом: чо вы все до этого злощастного энумератора докопались, ну тормозит он малость, но даже с ним работает быстрее.
 smile 


Автор: diadiavova 9.2.2009, 12:44
Чойт опять сообщение дублируется

Автор: Veon 9.2.2009, 12:56
Цитата(diadiavova @  9.2.2009,  10:44 Найти цитируемый пост)
В 10 раз - это ты загнул. 


Цитата(Veon @  8.2.2009,  20:18 Найти цитируемый пост)
Время затраченное на выполнение алгоритма без преобразования в число
196
Время затраченное на выполнение алгоритма с преобразованием в число
227
Время затраченное на alg3
17
Время затраченное на alg4
17


Да, загнул, в 11.5 раз
А учитывая foreach с case - в 14 smile

Хм, на рабочей машине результаты другие, метод с массивами в 3 раза быстрее метода с 9 case.

Автор: PashaPash 9.2.2009, 14:21
diadiavova, да ладно отпираться, просто признайся что написал кривой код - и мы от тебя отстанем smile

Автор: diadiavova 9.2.2009, 15:54
Veon, На моей машине после замены энумератора форичем время на выполнение сократилось в ~1,5 раза.


PashaPash, А дело не в коде, а в подходе к решению конкретной задачи. Ты используешь шаблонный подход со стандартными алгоритмами, а я подхожу к вопросу более гибко smile 
Цитата

Гибше надо быть. А на вещи смотреть - ширше.

smile

Автор: diadiavova 9.2.2009, 16:38
Проверил первоначальный код. Парсить по одному символу(предварительно преобразовав в строку) - идея действительно плохая(признаю smile ) нашёл другой выход
Код

        static void Main(string[] args)
        {
            string buf;
            Console.WriteLine("Введите целое число");
            buf = Console.ReadLine();
            int a = 0;
            int b = 0;
          foreach (char ch in buf)
            {
        if (ch == '-') { continue; }
        int cur = ch - '0';
                if (cur % 2 == 0)
                {
                    a++;
                }
                else
                {
                    b++;
                };
            };
            Console.WriteLine("Количество четных цифр " + a.ToString() + " в числе " + buf);
            Console.WriteLine("Количество не четных цифр " + b.ToString() + " в числе " + buf);
            Console.ReadLine();
        }

Автор: Partizan 9.2.2009, 16:45
diadiavova, проверьте на числе "---------"  ;)

Автор: diadiavova 9.2.2009, 16:47
Да, как бы, обсуждали это уже несколько раз. Изначально условились исходить из того, что вводимые данные корректны. 

Автор: Veon 9.2.2009, 16:53
Код

int cur = ch - '0';
                if (cur % 2 == 0)


Ну тогда уж можно и
Код

                if (ch % 2 == 1)



Код 0 - 48, код 1 - 49 и т.д. smile

К чему бы еще придраться..
Код

Console.WriteLine("Количество четных цифр " + a.ToString() + " в числе " + buf);

Код

Console.WriteLine("Количество четных цифр {0} в числе {1} ", a, buf);

smile

Автор: diadiavova 9.2.2009, 16:55
Это понятно. Правда не понятно почему ch % 2 == 1, если чётным числам соответствуют чётные коды и наоборот.

Автор: Partizan 9.2.2009, 16:55
diadiavova А, ну ок smile 

з.ы. /me думает закончится ли троллинг на 4 странице

Автор: Veon 9.2.2009, 16:58
Да устроили code review smile

Автор: diadiavova 9.2.2009, 17:09
Цитата(Partizan @  9.2.2009,  16:55 Найти цитируемый пост)
з.ы. /me думает закончится ли троллинг на 4 странице

Это не троллинг, а срач. При троллинге всегда есть пострадавшие.

Автор: crin 9.2.2009, 17:10
Код

static void Main(string[] args)
{
    string buf;
    Console.WriteLine("Введите целое число");
    buf = Console.ReadLine();
    int a = 0;
    int b = 0;
    int i = 0;
    if (buf[0] == '-')
        i++;

    for (; i < buf.Length; i++)
    {
        int cur = ch - '0';
        if (cur & 1 == 0)
            a++;
        else
            b++;  
    }
    Console.WriteLine("Количество четных цифр " + a.ToString() + " в числе " + buf);
    Console.WriteLine("Количество не четных цифр " + b.ToString() + " в числе " + buf);
    Console.ReadLine();
}

Автор: Partizan 9.2.2009, 17:20
crin

Код

if (cur & 1 == 0)


это круто =)

Автор: PashaPash 9.2.2009, 20:09
Цитата(diadiavova @  9.2.2009,  15:54 Найти цитируемый пост)
PashaPash, А дело не в коде, а в подходе к решению конкретной задачи. Ты используешь шаблонный подход со стандартными алгоритмами, а я подхожу к вопросу более гибко smile 

Нафиг гибкость, она неэффективна. В написании софта не место творчеству smile
Цитата(diadiavova @  9.2.2009,  17:09 Найти цитируемый пост)
Это не троллинг, а срач. При троллинге всегда есть пострадавшие. 

А ты еще не страдаешь?
Цитата(crin @  9.2.2009,  17:10 Найти цитируемый пост)
if (cur & 1 == 0)

Скобок не хватает и 
            bool b1 = (a % 2 == 0);
0000002e  mov         eax,dword ptr [rsp+20h] 
00000032  cdq              
00000033  and         eax,1 
....
;)

Автор: diadiavova 9.2.2009, 22:03
Цитата(PashaPash @  9.2.2009,  20:09 Найти цитируемый пост)
Нафиг гибкость, она неэффективна. В написании софта не место творчеству

Тогда твоих критериев эффективности я не понимаю.
 
Цитата(PashaPash @  9.2.2009,  20:09 Найти цитируемый пост)
А ты еще не страдаешь?


Интересно: с чего бы это? Да и я вообще к происходящему в интернетах отношусь весьма спокойно, так что, если ты хоте вывести кого-нибудь из себя, то жертву выбрал явно неудачно(я уже не говорю о том, что у тебя порой у самого нервы здают, а это уже не троллинг, а мазохизм).

Автор: Partizan 9.2.2009, 22:31
Цитата

00000033  and         eax,1 


PashaPash, аааааа  smile 

Ща в мозгу операцию провернул опять...каюсь...протупил   smile 

Автор: Veon 9.2.2009, 22:52
Цитата(PashaPash @  9.2.2009,  18:09 Найти цитируемый пост)
00000033  and         eax,1 

Зря ты так, обломал великих оптимизаторов :(

Странно что еще не предлогали

Код

foreach (char c in str)
{
    if ("02468".IndexOf(cur) >= 0)
    ....
}


Ведь судя по этому

Цитата(diadiavova @  9.2.2009,  09:24 Найти цитируемый пост)
На васике выглядит так

Select Case buf
    Case "0"c," 2"c, "4"c, "6"c, "8"c
        a+=1
    Case "1"c," 3"c, "5"c, "7"c, "9"c
        b+=1
End Select

То бишь  -  2 инструкции кейс вместо 10.


Это 1 инструкия  smile 

Автор: Partizan 9.2.2009, 23:22
Ладно, ребят...заканчиваем....
топик исчерпан... smile
Посмеялись и хватит smile

Автор: Veon 9.2.2009, 23:56
Ок, топик конечно давно превратился в стёб. Но такой вопрос.

Домашний комп почти как на работе, только проц e8300 а не e8400, дома стоит 2008 server 64 bit, на работе 2003 server 32 bit
Результат с методом в массиве
дома        16-17 мс
На работе    15 мс
Рузультат с методом в 10 case
дома        14 мс
на работе    45-46 мс
Каким макаром? Что влияет на предсказание ветвлений? smile
Результат с массивом вполне совпадает с разницей в частоте.

Автор: diadiavova 10.2.2009, 00:02
Veon, О примере на васике. О количестве инструкций речи вообще не было. Я написал только о том, что на васике тот же самый код занимает меньше писанины. А поскольку, пишу я именно на нём(шарп не люблю) для меня это существенно.

Автор: PashaPash 10.2.2009, 00:36
Цитата(Veon @  9.2.2009,  22:52 Найти цитируемый пост)
Зря ты так, обломал великих оптимизаторов :(

Странно что еще не предлогали

На домашней машине у меня там and eax,80000001h вместо cdq/and 1. так что оптимизация имеет право на жизнь, в разумных пределах. 
Цитата(Veon @  9.2.2009,  23:56 Найти цитируемый пост)
Каким макаром? Что влияет на предсказание ветвлений?

Битность и AnyCpu. Ну и прочие неявные показатели - разница между 2008 и 2003 например. smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)