Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Общие вопросы по .NET и C# > Разбитие целого числа на цифры. |
Автор: zaksys 5.2.2009, 18:08 | ||
У меня есть такая задача. Есть целое число, которое мы вводим с клавиатуры. И необходимо узнать сколько в этом числе нечетных и четных цифр. Примерно был написан такой код.
Подскажите, где здесь ошибка пожалуйста. |
Автор: diadiavova 5.2.2009, 18:45 | ||
Правда, в дополнение к этому ещё неплохо было бы проверить корректность введённых данных. |
Автор: zaksys 5.2.2009, 19:39 | ||
А можно объснить откуда это взялось, и что можно по этой теме почитать? |
Автор: diadiavova 5.2.2009, 19:44 |
Почитать попробуй официальную документацию по этому интерфейсу. Перечислитель просто перебирает буквы в строке. Метод MoveNext переводит его на следующую букву и есле она ещё есть, то возвращает true, в противном случае(если строка кончилась) цикл обрывается. Свойство Current возвращает текущую букву. |
Автор: 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 | ||
diadiavova, QryStaL, я просто в шоке. Считать четные/нечетные цифры преобразованием числа в строку - это позор. Оба примера падают даже на -1 ![]() Добавлено через 5 минут и 9 секунд
шаблон "Остаток от деления на 10" (с) |
Автор: diadiavova 6.2.2009, 17:14 |
PashaPash, я тебя ещё больше шокирую. В дополнение к тому позору, о котором ты уже написал, я ещё плюс ко всему не смог найти в своём собственном коде того места, в котором я преобразовывал бы число в строку с вышеозначенной целью. Так что: не сочти за труд - укажи место поточнее. ![]() |
Автор: PashaPash 6.2.2009, 17:21 |
Ты работаешь со строковым представлением числа. Выше у тебя уже есть готовое число в виде int. Это как-бы и есть преобразование числа в строку для решения мегазадачи ![]() |
Автор: diadiavova 6.2.2009, 17:37 |
Со строкой я работаю в силу того, что задача состоит в подсчёте цифр(которые как известно являются символами), из-за этого, на мой взгляд их куда более естественно извлекать прямо из строки, чем выполнять математические операции над числом после преобразования. Что до отрицательных чисел и прочих прелестей - это всё можно скорректировать если такое условие будет поставлено, насколько я понимаю, в твоём коде тоже отсутствует проверка корректности введённых данных ( только какое это имеет отношение к задаче?). Для проверки чётности я использовал тот же механизм что и ты(а не преобразование в строку). Что касается ручного энумератора, то здесь я, пожалуй, согласен, только вот...недостаток этот исправил QryStaL, но он тебя тоже почему-то шокировал. Я же его использовал для сохранения сходства с первоначальным кодом, для пущей ясности, пропёрся малость - бывает. ....Или ты опять намекаешь, что я про форич не в курсях? |
Автор: QryStaL 6.2.2009, 17:45 |
PashaPash, начнем с того, что я алгоритм вообще никак не комментировал, а просто ответил на вопрос автора про кусок кода (указал на возможность использования конструкции foreach) ![]() |
Автор: zaksys 6.2.2009, 18:19 |
Не понятно о чем тут написано, но все равно спасибо за помощь. |
Автор: PashaPash 6.2.2009, 18:53 | ||||
QryStaL, да с тобой все понятно ![]()
Да, только для опередления цифр, стоящих в десятичной записи числа есть готовый древний алгоритм с делением. Код пишется для машины, в которой числа представлены не строковыми литералами. И преобразование их в строки равносильно проверке val==true кодом типа if (val.ToString().Length == 4). Твой код считает количество четных одноразраядных чисел в введенной строке. Самого понятия "введенного числа" в нем нет. Как-то видет - для передачи массива чисел по сети их преобразовывали в строчку. И аргументировали - send(char*), значит надо передать строку. ;)
В условии написано - целых чисел. Отрицательные натуральные - это целые. Условие уже поставлено, так что отрицательные числа имеют к задаче вполне конкретное отношение ![]() |
Автор: diadiavova 6.2.2009, 20:02 |
zaksys, спор идёт о способе решения твоей задачи. В варианте, предложенном мной, строка просто перебирается посимвольно, и каждый символ проверяется на предмет соответствия условию. В варианте, предлагаемом PashaPash строку сначала надо преобразовать в число, а потом выдирать из этого числа отдельные цифры, используя простой(по его мнению) алгоритм, состоящий в том, что число в каждой итерации цикла делится на 10, остаток деления проверяется на предмет деления на 2 а с результатом деления эта операция повторяется до тех пор, пока он не иссякнет (я ничего не напутал?). PashaPash, в приведённом примере исходными данными является строка, так что: никто ничего не преобразовывал. Преобразовывать входную строку в число - действительно не надо было(переменная i там лишняя). Ну если ты так строго подходишь к этому учебному примеру и хочешь сделать из него настоящую программу, то "защиту от дурака" предусмотреть надо, несмотря на отсутствие такого требования в постановке задачи. |
Автор: PashaPash 6.2.2009, 20:14 | ||||
В приведенном условии встречаются слова "целое число". Скорее, преобразовывать каждый символ отдельно в число не надо было. А просто взять и написать стандартный алгоритм.
Вот такой я строгий и злой ![]() ![]() |
Автор: diadiavova 6.2.2009, 20:22 |
То, что мой код "падает" на отрицательных числах - всего навсего небольшой недочёт, который исправляется элементарно(уверен: ты и сам это понимаешь). Ты так на этом зацикливаешься, что создаётся впечатление, как будто попытка исправить этот недочёт способна убить алгоритм. В любом случае: перебрать строку - проще и дешевле, чем выполнять арифметические операции над числом(полученным из этой же строки) для получения того же результата. |
Автор: PashaPash 6.2.2009, 20:49 | ||||
Проще и дешевле??? С каких это пор преобразование строки в число (для каждого символа) стало проще и дешевле деления на 10 - одной процессорной инструкции? ![]() ![]() ![]()
Это большой недочет. Попытка исправления его подвинет алгортм на один шаг в сторону спагетти. Уверен, ты понимаешь сколько стоит выловить такой "недочет" в системе средних размеров. Так же уверен, что ты понимаешь что на самом деле для введения хоть какой-нибудь валидации ввода тебе придется обработать минимум 3 крайних случая вручную, и при этом повторить функционал стандартного Int32.Parse(). Хотя, после фразы что операция со строками дешевле деления - я уже не уверен ![]() |
Автор: zaksys 6.2.2009, 21:06 |
Я сначала думал перебрать преобразованное число по цифрам, и их сравнивать. Просто не знал как выделить из полученного числа цифры, чтоб потом просто проверить четные они не четные. |
Автор: diadiavova 6.2.2009, 21:11 | ||||
zaksys, ну тогда, вариант PashaPash для тебя. PashaPash, Сомневаюсь, что деление, с нахождением остатка - более дешёвая процедура, чем парсинг строки из одного символа. Хотя: спорить об этом умозрительно нет никакого смысла, а проверять на практике, я думаю не хочется ни тебе ни мне.
Ты хочешь сказать, что проверка наличия минуса в строке - настолько дорогое удовольствие, что слабой машине с этой сверзадачей не справиться?
Проверка введённых данных к теме имеет косвенное отношение, и если её вводить, то и расклад другой будет. |
Автор: PashaPash 6.2.2009, 21:23 | ||||
Деление с нахождением остатка - ровно одна инструкция процессора. Парсинг строки число в C# - это сложная операция, у четом текущей локали, кучи левых проверок типа на всякие там leading/traling space. Сложнее на пару порядков - возьми отладчик и убедись.
Я имею в виду что сам поиск такой ошибки будет достаточно трудоемкой операцией. Если даже 5 строчек не работают точно по однострочной спеке, то как можно доверить тебе проект? ![]() |
Автор: diadiavova 6.2.2009, 21:35 | ||||
Я имею в виду не поиск ошибки, а то, что код надо просто чуть-чуть подправить.
На сколько я понимаю, я к тебе на работу не устраиваюсь ![]() |
Автор: 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 | ||
Я так понимаю, что неодобрительную оценку я получил именно за это утверждение. В связи с этим, я немного подправил алгоритм(от преобразования строки в число отказался вовсе и заменил его свитчкейсом), решил проблему отрицательных чисел. Программа содержит текстовый файл, состоящий из 100000 строк, на каждой из которых записано целое число в интервале от -1000000 до 1000000 . Файл считывается построчно, и каждая строка передаётся на обработку первому алгоритму(моему), после чего аналогичные действия производятся со вторым алгоритмом. Время, затраченное на обработку выводится на экран. Файл сгенерирован рэндомно, метод при помощи которого это было сделано, представлен. |
Автор: zaksys 8.2.2009, 18:01 | ||||
А как решить проблему отрицательных чисел?(Чтоб их можно было безболезнено считывать, также как и положительные).
|
Автор: PashaPash 8.2.2009, 19:25 | ||||
Отмотай на мой пост на прошлой странице, там готовый код. Добавлено через 6 минут и 18 секунд
Не за это утверждение, а за общую кривизну решения детской задачи. |
Автор: diadiavova 8.2.2009, 20:55 |
А по поводу результатов теста будут комментарии? |
Автор: PashaPash 8.2.2009, 21:11 |
diadiavova, замечательный тест, вот только студии под рукой нет. А так - почему ты передаешь string buf? В условии ж сказано - целое число. Поменяй - получишь обратный результат ![]() И зачем ручная работа с энумератором? В чем вообще цель? Доказать что можно проверять на четность свитчем? Твой вариант препод завернет с фразой "а почему вы в число не преобразовываете как я вам показывал" ![]() ![]() |
Автор: diadiavova 8.2.2009, 21:18 |
Не надо передёргивать. Мы обсуждали вопрос о том, что проглотит меньше ресурсов. Тест был исключительно на эту тему. Первоначально ты мне доказывал, что преобразование в число "дешевле", теперь - откуда ни возьмись, нарисовался препод. "string buf" я передаю только потому, что с самого начала так сделал. В этом и состояла моя идея. И студия тут ни при чём - там есть бинарник. |
Автор: Veon 8.2.2009, 22:18 | ||||||
Ужасный тест ![]() Для единичного случая намного лучше подходи то, что написал PashaPash. Если уж ты хочешь обрабатывать большое кол-во строк, то есть намного лучше способы чем этот case ![]() Кое-чего поправил, чтобы более обьективно было Убрал
Лучше тест проводить на готовом массиве строк. Твоя прога с исправлениями (3-й способ работает только для положительных, можно его выкинуть)
Да, еще попробовал как оно работает на 1кк строк, после вызова твоего createFile немного офигел ![]() И проводи тесты лучше в release ![]() Зы: мои результаты Время затраченное на выполнение алгоритма без преобразования в число 196 Время затраченное на выполнение алгоритма с преобразованием в число 227 Время затраченное на alg3 17 Время затраченное на alg4 17 Хотя если в твоем методе с case поправить на
выдает 14 ![]() |
Автор: diadiavova 9.2.2009, 01:38 |
Это зря, оно как бы подразумевалось, забивать все данные в память не всегда целесообразно. Относительно метода CreateFile делать его идеальным я не собирался, потому, что в программе он не используется, написан на скорую руку, вызван единственный раз. Сделал своё дело и свободен. Оставил я его только для сведения о том, как был сформирован файл. При замене энумератора форичем код действительно работает быстрее(не знал). Твои алгоритмы действительно показывают лучшие результаты. Тест надо запускать несколько раз, поскольк результаты могут отличаться. Идеальным вариантом было бы прогнать по каждому алгоритму несколько раз и выводить усреднённые значения, хотя...и так всё видно. Кроме того: в качестве результата выводятся только миллисекунды, но если запустить тест на слабой машине могут и секунды возникнуть , а учтены они не будут(это я так на всякий случай). вместо a1.Milliseconds.ToString() надо писать a1.ToString(). Это для полноты картины. В любом случае, в контексте темы, вывод один... |
Автор: PashaPash 9.2.2009, 02:17 | ||
Не надо передергивать. Я сказал про преобразование каждого символа в число vs деление. Прогони свой первоначальный вариант ![]() ![]() Какой? И, кстати, DateTime+TimeSpan => System.Diagnostics.Stopwatch. |
Автор: diadiavova 9.2.2009, 11:24 | ||||||||
Не надо передёргивать: мой первоначальный вариант подвергся критике по совершенно другому поводу.
Далее, после уточнения, что я этого не делаю(здесь ты просто пропёрся, по этому поводу претензий нет - со всеми бывает) ты заявил следующее И дальнейший спор развивался в контексте вопроса, что в данном случае лучше - преобразование в число или работа со строкой. И кстати: я не понял, ты уже не споришь с тем, что в данном конкретном случае лучше обрабатывать строку непосредственно? ![]() Идея со свитчкейсом была с самого начала, просто в шарпе она не очень удобная, из-за этого я сократил малость(я же не думал, что мой код будет рассматриваться под микроскопом). Код
На васике выглядит так
То бишь - 2 инструкции кейс вместо 10. По-моему мы говорили о скорости работы алгоритмов. А это ты к чему? |
Автор: PashaPash 9.2.2009, 11:42 | ||||||||
отдельно о скорости, обычно об общем подходе.О скорости:
Вроде бы спор о производительности я утверждал только вот это. И первоначальный вариант я критиковал именно за "двойное преобразование". Точнее, за цепочку "уже готовый string->int игнорируется"->"возврат к строке"->"ручной энумератор"->"боксинг/анбоксинг"->"преобразование char в string (посимвольное)"->"преобразование string->int (посимвольно)". Видишь тут аж 5 (!) кастов каждого символа? А можно было сделать всего один, и обойтись делением.
В данном конкретном случае это явно задача с каких нибудь курсов. И цель ее явно не научить перебирать символы в строке, а научить работать с целыми числами, делить с остатком и проверять четность. Задачи "найти количество символов 0 2 4 6 8 и 1 3 5 7 9" формулируются обычно совсем по-другому. Мой вывод - если человека раздразнить - он вылижет совй код ![]() Добавлено через 43 секунды
Это класс специально для меряния временем. |
Автор: Veon 9.2.2009, 11:46 |
Ну вообще-то задача звучала так "Есть целое число, которое мы вводим с клавиатуры. И необходимо узнать сколько в этом числе нечетных и четных цифр. " В стандартном методе PashaPash как раз таки работают с числами, вставить туда TryParse и вообще будет хорошо. diadiavova же считает в строке количество символов '0', '1'... Проглотит число qqq1aaa? На моей машине 9 case работают быстрее чем с массивами. Я думал что будет наоборот. Пример с массивами я приводил только чтобы показать, что есть методы быстрее твоего (ошибся и не привел ![]() А ты занимаешься преждевременной оптимизацией. Мало того что нет таких сферических прог в которых нужно обрабатывать миллионы строк, так в 1-й раз ты парсил каждую цифру, а во второй использовал Enumerator. Вести спор о ресурсах и скорости вычисления, когда за 10 секунд можно набрасать метод работающий аналогично твоему (не PashaPash), но в 10 раз быстрее ![]() Блин, пока писал уже то-же самое ответили ![]() |
Автор: diadiavova 9.2.2009, 12:44 | ||||||||||||
Для того, чтобы обсуждать общий подход, надо определиться для начала с критериями оценки оновго подхода. Я скопипастил исходный пример и исправлял его. Учитывая, что я применил другой подход, исправлять надо было более радикально. При дальнейшем обсуждении я написал, что в число преобразовывать вообще н следовало и мы это обсуждали. Возврата не было, я просто проигнорировал преобразованное число, ещё раз повторяю, что если бы я сам писал код с самого начала, то строку вообще не парсил бы. Здесь согласен(учитывая результаты теста). Здесь тоже спорить не буду, хотя твой "праведный гнев" был направлен совсем в другую сторону. Возникает интересная ситуация: первоначально ты критикуешь непосредственную работу со строкой, потом, когда выясняется, что критика была неуместной, начинаешь придираться к деталям, возникшим вследствие того, что код писался "не на выставку". Да нет, ещё и вот это как бы имеет отношение к делу
Напомню: речь шла о "падении на отрицательных". Куда подвинула попытка его исправления мы видели - алгоритм заработал быстрее.
Возможно, только
Раз ты так уж уповаешь на условия, то давай не будем от них отступать. В условии шла речь о решении конкретной задачи, а не о способе её решения. Для того, чтобы "вылизать" код надо, как минимум знатькак это сделать. Вся фишка в том, что общую концепцию я не изменил при "вылизывании". Я всё равно обрабатываю строку непосредственно и алгоритм работает быстрее твого ![]()
В программу число попадает в виде текста, в этом вся суть. Если бы исходные данные были числовыми, то и разговор был бы другим. В процессе обсуддения уже звучала мысль, что в условии речи о валидации не шло(то бишь: предполагается, что данные вводятся корректно), если требуется валидация, то и расклад(опять-таки) другой. Проверка данных - процедура недешёвая. Если исходить из предположения, что данные вводятся корректно, то выполнять её - расточительство.
В 10 раз - это ты загнул. И потом: чо вы все до этого злощастного энумератора докопались, ну тормозит он малость, но даже с ним работает быстрее. ![]() |
Автор: diadiavova 9.2.2009, 12:44 |
Чойт опять сообщение дублируется |
Автор: Veon 9.2.2009, 12:56 | ||
Да, загнул, в 11.5 раз А учитывая foreach с case - в 14 ![]() Хм, на рабочей машине результаты другие, метод с массивами в 3 раза быстрее метода с 9 case. |
Автор: PashaPash 9.2.2009, 14:21 |
diadiavova, да ладно отпираться, просто признайся что написал кривой код - и мы от тебя отстанем ![]() |
Автор: diadiavova 9.2.2009, 15:54 | ||
Veon, На моей машине после замены энумератора форичем время на выполнение сократилось в ~1,5 раза. PashaPash, А дело не в коде, а в подходе к решению конкретной задачи. Ты используешь шаблонный подход со стандартными алгоритмами, а я подхожу к вопросу более гибко ![]()
![]() |
Автор: diadiavova 9.2.2009, 16:38 | ||
Проверил первоначальный код. Парсить по одному символу(предварительно преобразовав в строку) - идея действительно плохая(признаю ![]()
|
Автор: Partizan 9.2.2009, 16:45 |
diadiavova, проверьте на числе "---------" ;) |
Автор: diadiavova 9.2.2009, 16:47 |
Да, как бы, обсуждали это уже несколько раз. Изначально условились исходить из того, что вводимые данные корректны. |
Автор: Veon 9.2.2009, 16:53 | ||||||||
Ну тогда уж можно и
Код 0 - 48, код 1 - 49 и т.д. ![]() К чему бы еще придраться..
![]() |
Автор: diadiavova 9.2.2009, 16:55 |
Это понятно. Правда не понятно почему ch % 2 == 1, если чётным числам соответствуют чётные коды и наоборот. |
Автор: Partizan 9.2.2009, 16:55 |
diadiavova А, ну ок ![]() з.ы. /me думает закончится ли троллинг на 4 странице |
Автор: Veon 9.2.2009, 16:58 |
Да устроили code review ![]() |
Автор: diadiavova 9.2.2009, 17:09 |
Это не троллинг, а срач. При троллинге всегда есть пострадавшие. |
Автор: crin 9.2.2009, 17:10 | ||
|
Автор: Partizan 9.2.2009, 17:20 | ||
crin,
это круто =) |
Автор: PashaPash 9.2.2009, 20:09 | ||||
Нафиг гибкость, она неэффективна. В написании софта не место творчеству ![]()
А ты еще не страдаешь? Скобок не хватает и bool b1 = (a % 2 == 0); 0000002e mov eax,dword ptr [rsp+20h] 00000032 cdq 00000033 and eax,1 .... ;) |
Автор: diadiavova 9.2.2009, 22:03 | ||
Тогда твоих критериев эффективности я не понимаю. Интересно: с чего бы это? Да и я вообще к происходящему в интернетах отношусь весьма спокойно, так что, если ты хоте вывести кого-нибудь из себя, то жертву выбрал явно неудачно(я уже не говорю о том, что у тебя порой у самого нервы здают, а это уже не троллинг, а мазохизм). |
Автор: Partizan 9.2.2009, 22:31 | ||
PashaPash, аааааа ![]() Ща в мозгу операцию провернул опять...каюсь...протупил ![]() |
Автор: Veon 9.2.2009, 22:52 | ||||
Зря ты так, обломал великих оптимизаторов :( Странно что еще не предлогали
Ведь судя по этому
Это 1 инструкия ![]() |
Автор: Partizan 9.2.2009, 23:22 |
Ладно, ребят...заканчиваем.... топик исчерпан... ![]() Посмеялись и хватит ![]() |
Автор: Veon 9.2.2009, 23:56 |
Ок, топик конечно давно превратился в стёб. Но такой вопрос. Домашний комп почти как на работе, только проц e8300 а не e8400, дома стоит 2008 server 64 bit, на работе 2003 server 32 bit Результат с методом в массиве дома 16-17 мс На работе 15 мс Рузультат с методом в 10 case дома 14 мс на работе 45-46 мс Каким макаром? Что влияет на предсказание ветвлений? ![]() Результат с массивом вполне совпадает с разницей в частоте. |
Автор: diadiavova 10.2.2009, 00:02 |
Veon, О примере на васике. О количестве инструкций речи вообще не было. Я написал только о том, что на васике тот же самый код занимает меньше писанины. А поскольку, пишу я именно на нём(шарп не люблю) для меня это существенно. |
Автор: PashaPash 10.2.2009, 00:36 | ||
На домашней машине у меня там and eax,80000001h вместо cdq/and 1. так что оптимизация имеет право на жизнь, в разумных пределах. Битность и AnyCpu. Ну и прочие неявные показатели - разница между 2008 и 2003 например. ![]() |