А прочитать название ошибки - не? Сложно?
Я имел в виду, почему число = 536870897, не больше и не меньше: вроде бы оно не равно ни одной из констант в справке?
Потому что в тот момент памяти хватило именно на такой размер.
Это как Вы с рынка приходите, купили там себе морковку за 11 рублей и 70 копеек, потому что продавец сказал “Ладно, давай сколько у тебя есть”, а у Вас допытываются, почему морковка по некруглой цене.
А как в моей программе ограничить это число до максимального допустимого (чтобы невозможно было набрать такое, при котором в определённый момент времени не хватит памяти)?
Как я понимаю, это не относится к физической памяти, так как 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.
Да, это ограничение CLR. В студии, правда, если поставить платформу x64 и добавить в конфиг:
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
То можно выделять и больше 2 ГБ за раз. Без чего-то из этого вылетает та самая ошибка.
И то, работать это будет только с .NET 4.5+
Непонятно, почему микроскоп стоит такие большие деньги? Обычный копеечный молоток забивает гвозди гораздо лучше!
гроба
С гробом - тут сложнее. Там гвозди не забивают, а вколачивают. Да и то в крышку.
Почему при следующем коде программы переменная 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.