Помощь новичкам

А прочитать название ошибки - не? Сложно?

Я имел в виду, почему число = 536870897, не больше и не меньше: вроде бы оно не равно ни одной из констант в справке?

Потому что в тот момент памяти хватило именно на такой размер.

Это как Вы с рынка приходите, купили там себе морковку за 11 рублей и 70 копеек, потому что продавец сказал “Ладно, давай сколько у тебя есть”, а у Вас допытываются, почему морковка по некруглой цене.

1 лайк

А как в моей программе ограничить это число до максимального допустимого (чтобы невозможно было набрать такое, при котором в определённый момент времени не хватит памяти)?

Как я понимаю, это не относится к физической памяти, так как 500M integer’ов это всего 2 гб, а у меня 16. @Sun_Serega, это ведь ограничение CLR?

Вообще не знаю, но что то я кажись понял. Ограничение накладывается на кол-во байт. А оно не может быть >2^31-1. Вполне возможно что для какой то внутренней кухни CLR.

И не забываем про заголовок, с размером массива и т.п., поэтому там не -1.

Ну, в любом случае, @Just_name, если вам нужны такие большие массивы - вы явно делаете что то не так. Кроме того что их обработка займёт слишком долго - вам вряд ли понадобится что сразу 536870898 элементов были в памяти. Храните большую часть в файле и загружайте отдельные части на обработку по необходимости.

Функционал для этого уже есть в BlockFileOfT:

uses BlockFileOfT;

begin
  var f := new BlockFileOf<integer>('0.bin');
  f.Rewrite;
  
  f.Size := int64(1) shl 33; // 32 гигабайта
  var a := new integer[1024];
  
  f.Pos := 1024*1024;
  f.Read(a);
  f.Flush; // обнуляем кеш, чтоб выбросить из оперативной памяти копию прочитанной области
  
  a.Fill(i->i);
  
  f.Pos := 1024*1024;
  f.Write(a);
  f.Flush; // сбрасываем изменения на диск, до этого вызова данные для записи хранятся в оперативной памяти
  
  f.Close;
end.
1 лайк

Да, это ограничение CLR. В студии, правда, если поставить платформу x64 и добавить в конфиг:

	<runtime>  
		<gcAllowVeryLargeObjects enabled="true" />  
	</runtime>

То можно выделять и больше 2 ГБ за раз. Без чего-то из этого вылетает та самая ошибка.

И то, работать это будет только с .NET 4.5+

Непонятно, почему микроскоп стоит такие большие деньги? Обычный копеечный молоток забивает гвозди гораздо лучше!

4 лайка

гроба

1 лайк

С гробом - тут сложнее. Там гвозди не забивают, а вколачивают. Да и то в крышку.

2 лайка

Почему при следующем коде программы переменная c равна “2”, а не “2.2307692…” и как изменить код, чтобы результат деления был правильным?

var
  a, b: BigInteger;
  c: real;
begin
  a:=29;
  b:=13;
  c:=real(a/b);
  Writeln('c = ', c, '.');
end.

Конвертируйте тип до применения оператора.

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

Как это выглядит в коде программы?

real(a)/b. Вообще обычно надо и b конвертировать, но тут это само произойдёт.

А тут a и b могут быть любыми целыми и всё равно не будет ошибки и c вычислится правильно?

Для integer и т.п. это и не надо, у них тип и так конвертируется в real перед делением.

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

begin
  var a:=BigInteger(2*(Power(10,308)));
end.

выводится ошибка

Ошибка времени выполнения: System.OverflowException: BigInteger не может представлять бесконечное значение.

Я имел в виду следующее: если a и/или b будут огромными, то не выдаст ли ошибку типа “Такое большое BigInteger невозможно перевести в Real” и/или не будет ли деление выполнено с неверным результатом.

Другой вопрос: как сделать так, чтобы, когда вводят неправильное значение (больше числа, меньше числа и значение типа, который невозможно преобразовать в Integer), выводило сообщение “Ошибка… (причина)” и запрашивало ввод в эту же переменную заново, а то я делаю это следующим образом:

begin
  Writeln('(Объяснение требуемого типа и значения.)');
  var a:=ReadReal;
  if not ((a>=2) and (a<=5)) then
  begin
    repeat
      Writeln('Ошибка. Заданное значение не соответствует диапазону.');
      Writeln('(Объяснение требуемого типа и значения.)');
      a:=ReadReal;
    until (a>=2) and (a<=5);
  end;
end.

при котором всё равно выводится исключение, если, например, в поле ввода от ReadInteger ввели String.

BigInteger может представить любое больное конечное число. А 2*(Power(10,308)) слишком больше для real, поэтому оно превращается в real.Infinity.

Ошибки не будет, только опять получите real.Infinity.

begin
  var i: integer;
  while not TryRead(i) or not i.InRange(1,2) do Writeln('Неправильное значение');
end.

Или разные ошибки:

begin
  var i: integer;
  while true do
    if not TryRead(i) then Writeln('Нужно число') else
    if not i.InRange(1,2) then Writeln('Вне диапазона') else
      break;
end.

Потому что нужен другой Power.

begin
  var a:=BigInteger(2*(BigInteger.Pow(10,308)));
end.