LINUX.ORG.RU
ФорумTalks

Задача про нахождение суммы ряда чисел _без_ циклов

 , ,


0

1

Здравствуйте, дорогие любители математики и программирования!

Начинаем нашу будничную ЛОРовскую викторину на программирование и математику. Собственно, она больше на математику чем на программирование (поэтому и ответы, внезапно, могут быть разными).

Итакъ, поехали. Задача: написать программу, которая принимает на вход целые числа A и B и выводит сумму ряда целых чисел от A до B включительно. При этом перебирать числа в цикле _нельзя_. Никаких for, while, until, repeat,... и т.д.

Пример работы готовой программы:

> ./sumatob 24 40007
800299752
> ./sumatob 369 1001
433605
> ./sumatob -5000 100001
4987647501
>
Пользоваться Гуглом при решении задачи не запрещается.

Моё решение этой задачи здесь: https://saahriktu.org/downloads/sumatob.tar.xz

★★★★★

Ответ на: комментарий от gremlin_the_red

«func(x) = bool» - это boolean expression condition или нет? Таки да.

А if как раз и введён чтобы писать «if <boolean expression condition> then».

saahriktu ★★★★★
() автор топика
Ответ на: комментарий от saahriktu

Лучше не использовать atoi. Про это написано в ATOI(3):

BUGS
       errno  is  not  set  on  error so there is no way to distinguish between 0 as an error and as the converted value.  No checks for overflow or underflow are done.
       Only base-10 input can be converted.  It is recommended to instead use the strtol() and strtoul() family of functions in new programs.
kmeaw ★★★
()

Здравствуйте, дорогие любители математики и программирования!

Здравствуйте!

Задача: написать программу, которая принимает на вход целые числа A и B и выводит сумму ряда целых чисел от A до B включительно.

Есть правило Гаусса.

При этом перебирать числа в цикле нельзя. Никаких for, while, until, repeat,… и т.д.

Если кто не вспомнит Гаусса, то рекурсия или sum(range(a,b+1)). Кроме того, в классическом Basic циклы лепили руками из одних только IF и GOTO.

Моё решение этой задачи здесь

Скачай, распакуй, открой. Нет, не хочу.

Bagrov ★★★★★
()
Последнее исправление: Bagrov (всего исправлений: 1)
Ответ на: комментарий от saahriktu

Ты фундаментально не можешь понять, что именно ты делаешь не так, или это тонкий троллинг?

Второй вопрос: а учиться ты принципиально считаешь плохой идеей?

Shaman007 ★★★★★
()
Ответ на: комментарий от Shaman007

Да знаю я знаю, что хорошим тоном считается указывать юзеру на несоответствие типов вводимых им данных. Однако, ошибки юзера возможны не только в типах данных, но и в самих вводимых им данных. И кто будет проверять правильно ли юзер ввёл, например, 5.3, когда на самом деле он должен был ввести, например, 12.13? В любом случае самому юзеру нужно следить за тем, что он вводит. Иначе он так и будет получать не то, что ему нужно.

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

saahriktu ★★★★★
() автор топика
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от gremlin_the_red
if (True == True) != False:
   gremlin_the_red.say_something_obvious(source=Wirth)

А если серьезно, то дело говоришь. Даже не могу представить, где такие проверки могут пригодиться, когда есть if и if not.

Bagrov ★★★★★
()
Ответ на: комментарий от gag

У @saahriktu тут нет бага. Переполнение произойдёт намного раньше.

Одно то, что он переходит к double, значит что диапазон представимых значений сужается до по модулю не превосходящих 2^53 - 1 вместо 2^64-1

Плюс умножение.

(a + b) / 2 не релевантно к этому коду, так как не изменит корректность ни для каких значений как бы мы это не посчитали.

fsb4000 ★★★★★
()
Ответ на: комментарий от gag

А взял бы весь числитель в скобки и уже мог бы избежать такого косяка.

grem ★★★★★
()
Ответ на: комментарий от fsb4000

(a + b) / 2

Есть гарантия, что деление произойдёт после умножения?

Он оперирует целыми числами и внезапно в результате промежуточного действия возникает число x.5.

У него ещё и ненужный вообще trunc используется.

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 1)
Ответ на: комментарий от gag

Я тут, кстати, тест набросал. Ближе к максимальному значению Int64 погрешность становится равна единице.

program int64fltdivtest;
var
   a, b :  Int64;
begin
   a := trunc($7FFFFFFFFFFFFFFF / 2);
   b := $7FFFFFFFFFFFFFFF shr 1;
   writeln(a, sLineBreak, b);
end.
> ./int64fltdivtest
4611686018427387904
4611686018427387903
>
А при числах до 9223372036854774784 ($7FFFFFFFFFFFFC00) погрешность равна нулю.

saahriktu ★★★★★
() автор топика
Ответ на: комментарий от saahriktu

Я тут тоже тест набросал.

uses SysUtils;
var
  a, b, s: Int64;
begin
  a:=StrToInt64(ParamStr(1));
  b:=StrToInt64(ParamStr(2));
  s:=trunc((b-a+1)*(a+b)/2);
  Writeln('S:', s);
end.
$ k='1' ; for i in `seq 1 20` ; do k="${k}0"; ./test 1 $k ; done
S:55
S:5050
S:500500
S:50005000
S:5000050000
S:500000500000
S:50000005000000
S:5000000050000000
S:500000000500000000
An unhandled exception occurred at $00000000004002D7:
EIntOverflow: Arithmetic overflow
  $00000000004002D7
gremlin_the_red ★★★★★
()
Ответ на: комментарий от saahriktu

Тебе явно нужны проверки для ограничения вводимых чисел

grem ★★★★★
()
Ответ на: комментарий от saahriktu

Хотел написать, что лучше бы ты полезным чем занялся и помогал писать или патчить doublecommander. Но, пожалуй, лучше продолжай заниматься тем же чем сейчас.

grem ★★★★★
()
Ответ на: комментарий от gremlin_the_red

Нужно использовать TryStrToInt64() и проверять не возвращает ли она False. А то так можно и ввести число, которое не влезет в Int64.

saahriktu ★★★★★
() автор топика
Ответ на: комментарий от gremlin_the_red
> k='1' ; for i in `seq 1 20` ; do k="${k}0"; ./sumatob 1 $k ; done
55
5050
500500
50005000
5000050000
500000500000
50000005000000
5000000050000000
500000000500000000
3883139820726120960
932356074711512064
1001882602603448320
7954494891797073920
2239044010196672512
2538972135152631808
4821168520184233984
2051506101975056384
6959797423555346432
Error: invalid number B
Error: invalid number B
>
saahriktu ★★★★★
() автор топика
Ответ на: комментарий от saahriktu

А при числах до 9223372036854774784 ($7FFFFFFFFFFFFC00) погрешность равна нулю.

Нет. Погрешность начнётся с 2^53

/ возвращает real тип. Этот тип является double (8 байт) в современном fpc.

double может без потери точности представить целые числа лишь до 2^53.

Вот тебе пример, лишь посчитаем сумму 100 чисел от 2^53:

(* program that sums integer values from A to B without loops
   2020 (c) saahriktu
   Under GNU GPLv3 *)
program sumatob;
uses sysutils;
var
   a, b, s, s2, s3, i : Int64;
begin
   a := 9007199254740992; // 2^53
   b := a + 100;

   s3 := 0;
   for i := a to b do begin
     inc(s3, i);
   end;

   s := trunc((b - a + 1) * (a + b) / 2);

   s2 := (b - a + 1) * (a + b) div 2;

   writeln(s);
   writeln(s2);
   writeln(s3);
end.
909727124728845184
909727124728845242
909727124728845242
fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000
> ./int64fltdivtest3
4611686018427387392
4611686018427387392
> cat int64fltdivtest3.pas
program int64fltdivtest3;
var
   a, b :  Int64;
begin
   a := trunc($7FFFFFFFFFFFFC00 / 2);
   b := $7FFFFFFFFFFFFC00 shr 1;
   writeln(a, sLineBreak, b);
end.
>
saahriktu ★★★★★
() автор топика
Ответ на: комментарий от fsb4000

Оперировать double вместо нормальных целых чисел это дичь. Но именно так в JS мире, где есть только double (и с недавних пор BigInteger, но в palemoon например его ещё нет).

Если ты не пишешь Web SPA, то используй настоящие целочисленные типы. double вместо int64 это дичь.

https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от saahriktu

Хотя, да, всё-таки погрешность может вылазить. Да, целочисленное деление надёжнее.

saahriktu ★★★★★
() автор топика

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

print('#include <stdlib.h>')
print('#include <stdio.h>')
print('int main(int argc, char *argv[]) {')
print('  if (argc <= 2) { printf("argc\\n"); exit(2); }')
print('  int a, b;')
print('  unsigned long s = 0;')
print('  sscanf(argv[1], "%d", &a);')
print('  sscanf(argv[2], "%d", &b);')
for i in range(-1_000_000, 1_000_001):
    print('  if (a <= {i} && {i} <= b) s += {i};'.format(i=i))
print('  printf("s = %ld\\n", s);')
print('  return 0;')
print('}')

В качестве компилятора рекомендую брать tcc.

i-rinat ★★★★★
()
Ответ на: комментарий от BceM_IIpuBeT

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

С другой стороны, я видел четверокурсников технического вуза, которые не знали,что такое цикл в программировании. А им на первом курсе как минимум один язык преподавали.

ТС хотя бы это знает и, авось, в какую-то сторону да движется.

grem ★★★★★
()
Ответ на: комментарий от Harald

Мащинлёрнинг на джаваскрипте, да!

(на блокчейне еще)

michwill ★★★★★
()
Ответ на: комментарий от BceM_IIpuBeT

Можно подумать, что вообще все люди помнят вообще все формулы школьной программы, особенно к 40-ка или 50-ти годам.

И, вообще, в математике редко когда бывает одно единственное решение.

saahriktu ★★★★★
() автор топика
Ответ на: комментарий от saahriktu

Вообще, к любому человеку, который берет на себя смелость начать игру «давайте подумаем», предъявляется как минимум 2 требования:

  • задача должна быть чем-то новой и чем-то интересной

  • афтар должен предоставить свое авторское решение, которое было бы интересным

Ты завалил обе задачи, потому что взял штуку даже не из Перельмана, Мартина или Маковецкого. Не говоря уже про Рамануджана, Харди или Литлвуда. Даже не эманации Смольякова, Эдуарда Римовича! Нет, учебник 9го класса, раздел «это интересно, посоны, что Гаусс в 6 лет придумал!». И решение ты предоставил не только тривиальное, из учебника, но и с ошибками.

Не надо так.

Shaman007 ★★★★★
()
Последнее исправление: Shaman007 (всего исправлений: 1)
Ответ на: комментарий от Shaman007

Рамануджана

Теперь человек будет неделю думать, как так получается, что складывая положительные числа, мы получим -1/12. А потом, того и гляди, вскроется.

Не надо так.

gremlin_the_red ★★★★★
()
Ответ на: комментарий от Shaman007

На ЛОРе бывают самые разные викторины.

Насколько я помню, одно время выкладывали фотографии с вопросом «А что это такое?». И все вспоминали что же это такое.

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

saahriktu ★★★★★
() автор топика
Ответ на: комментарий от Shaman007

Но, Шома! Критикуя - предлагай. Как надо-то?

Так вот, пилю прохладную.

Упомянутый выше Эдуард Римович в свободное от ловли инопланетян время преподавал нам спецглавы высшей математики (методист он ниочень, ученый - очень, охотник за приведениями и маг - ну уровень примерно 42й с капом в 50 по моей шаманской оценке). Нашлись 2 студента, которые в глаза называли его шизофреником (в отличие от меня, тупого отличника, который ничего не понимал, но ходил на все его лекции просто чтобы он знал мое щачло уверенно и нарисовал бы «отл» в зачетке просто от того, что я не прогорал на его лекциях, а слушал на сложных щщах. Это сработало, мне стыдно, но я овлекся). Римович обратился к этим студентам с челледжем: «вы решаете мне задачку, я вам ставлю ОТЛ за 2 семестра и мы больше не встречаемся». Он, потирая руки, дал им задачу из серии «1000 задач не решенных за тысячелетие», а они через 2 недели принесли ему решение, внимание, на Macromedia Flash. Двоечники, чо.

Но он человек честный, они опубликовались в каком-то большом американском журнале, получили респекты, теперь этот список из 999 задач.

Shaman007 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.