Объявление большого массива вызывает ошибку сегментации, но вектор не [дублирует]

Как отмечали некоторые другие, правильным ответом является использование либо DecimalFormat, либо BigDecimal. Плавающая точка не имеет десятичных мест , поэтому вы не можете округлить / усечь до определенного числа из них в первую очередь. Вы должны работать в десятичном радиксе, и это то, что делают эти два класса.

Я отправляю следующий код в качестве встречного примера для всех ответов в этом потоке и, действительно, по всему StackOverflow (и в другом месте), которые рекомендуют умножение с последующим усечением, за которым следует разделение. Для сторонников этой методики необходимо объяснить, почему следующий код производит неправильный вывод в более чем 92% случаев.

public class RoundingCounterExample
{

    static float roundOff(float x, int position)
    {
        float a = x;
        double temp = Math.pow(10.0, position);
        a *= temp;
        a = Math.round(a);
        return (a / (float)temp);
    }

    public static void main(String[] args)
    {
        float a = roundOff(0.0009434f,3);
        System.out.println("a="+a+" (a % .001)="+(a % 0.001));
        int count = 0, errors = 0;
        for (double x = 0.0; x < 1; x += 0.0001)
        {
            count++;
            double d = x;
            int scale = 2;
            double factor = Math.pow(10, scale);
            d = Math.round(d * factor) / factor;
            if ((d % 0.01) != 0.0)
            {
                System.out.println(d + " " + (d % 0.01));
                errors++;
            }
        }
        System.out.println(count + " trials " + errors + " errors");
    }
}

Вывод этой программы:

10001 trials 9251 errors

EDIT: Чтобы ответить на некоторые комментарии ниже, я отредактирую часть модуля тестового цикла с помощью BigDecimal и new MathContext(16) для работы модуля следующим образом:

public static void main(String[] args)
{
    int count = 0, errors = 0;
    int scale = 2;
    double factor = Math.pow(10, scale);
    MathContext mc = new MathContext(16, RoundingMode.DOWN);
    for (double x = 0.0; x < 1; x += 0.0001)
    {
        count++;
        double d = x;
        d = Math.round(d * factor) / factor;
        BigDecimal bd = new BigDecimal(d, mc);
        bd = bd.remainder(new BigDecimal("0.01"), mc);
        if (bd.multiply(BigDecimal.valueOf(100)).remainder(BigDecimal.ONE, mc).compareTo(BigDecimal.ZERO) != 0)
        {
            System.out.println(d + " " + bd);
            errors++;
        }
    }
    System.out.println(count + " trials " + errors + " errors");
}

Результат:

10001 trials 4401 errors
82
задан sth 4 December 2009 в 16:43
поделиться

5 ответов

Вероятно, вы просто получаете переполнение стека. Массив слишком велик, чтобы вставлять адресное пространство стека вашей программы.

Если вы выделяете массив в куче, вы должны быть в порядке, если у вас достаточно памяти.

int* array = new int[1000000];

Но помните, что это потребует от вас delete[] массива. Лучшим решением было бы использовать std::vector<int> и изменить его размер до 1000000 элементов.

96
ответ дан Charles Salvia 21 August 2018 в 07:50
поделиться
  • 1
    Спасибо за ответ, но не могли бы вы объяснить мне, почему массивы выделяются в стеке и почему не в основной программной памяти. – Mayank 4 December 2009 в 16:51
  • 2
    Данный код выделяется в стеке, потому что он задан как массив с постоянным числом элементов во время компиляции. Значения помещаются только в кучу с помощью malloc, new и т. Д. – Seth Johnson 4 December 2009 в 17:05
  • 3
    Все автоматические переменные выделяются в стеке. Если вы посмотрите на disasseble, вы увидите размер ваших локальных переменных, вычитаемых из указателя стека. Когда вы вызываете malloc или calloc или какие-либо из флагов памяти, fuctions заходят и находят блоки памяти, достаточно большие, чтобы удовлетворить ваши требования. – rerun 4 December 2009 в 17:12
  • 4
    @Charles, почему мы могли выделить больше памяти из кучи, а не из стека? из моего понимания, как стек, так и куча движутся в противоположном направлении в выделенном адресном пространстве в памяти. – saurabh agarwal 24 February 2015 в 07:58
  • 5
    @saurabhagarwal Куча не двигается. Это даже не смежная область памяти. Распределитель просто возвращает свободный блок памяти, который соответствует вашему требованию к размеру Что и где находится стек и куча? – phuclv 23 June 2015 в 04:45

В C или C ++ локальные объекты обычно выделяются в стеке. Вы выделяете большой массив в стеке, больше, чем может обрабатывать стек, поэтому вы получаете stackoverflow.

Не выделяйте его локально в стеке, используйте некоторые другие вместо этого. Этого можно достичь либо путем создания объекта global , либо выделения его в глобальной куче . Глобальные переменные прекрасны, если вы не используете их из любой другой единицы компиляции. Чтобы убедиться, что это не происходит случайно, добавьте спецификатор статического хранилища, иначе просто используйте кучу.

Это будет выделяться в сегменте BSS, который является частью кучи:

static int c[1000000];
int main()
{
   cout << "done\n";
   return 0;
}

Это будет выделяться в сегменте DATA, который также является частью кучи:

int c[1000000] = {};
int main()
{
   cout << "done\n";
   return 0;
}

Это будет выделяться в каком-то неуказанном месте в куче:

int main()
{
   int* c = new int[1000000];
   cout << "done\n";
   return 0;
}
46
ответ дан Community 21 August 2018 в 07:50
поделиться
  • 1
    Если вы используете третий шаблон, выделяя кучу, не забудьте удалить [] указатель на каком-то этапе или утечка памяти. Или посмотрите на умные указатели. – meowsqueak 5 September 2012 в 02:20
  • 2
    @meowsqueak Конечно, это хорошая практика delete, которую вы выделяете с помощью new. Но если вы уверены, что вы выделяете память только один раз (как в основном), она строго не нужна - гарантируется, что память будет освобождена при выходе из основного, даже без явного delete. – Gunther Piez 5 September 2012 в 09:11
  • 3
    'at'drhirsch (как вы все-таки играете?) - да, честный комментарий. Поскольку OP кажется новым для языка, я просто хотел убедиться, что они и любой другой, видя ваш хороший ответ, были осведомлены о последствиях третьего варианта, если они используются в целом. – meowsqueak 5 September 2012 в 13:19
  • 4
    @meowsqueak: зависит от вашей клавиатуры. Для меня это RightALT-L (Mac) или RightALT-Q (Windows). Вам нужно добавить & quot; @ & quot; символ, если вы хотите ответить на комментарий, чтобы автор оригинального комментария получил уведомление. В этом случае меня все равно замечают, потому что это был мой ответ. – Gunther Piez 5 September 2012 в 15:50
  • 5
    если я положил @ + drhirsch в начале моего комментария, @ и ваше имя исчезнут, даже из окна редактирования. Очень странно. Ну, это не место, чтобы разобраться в этом. – meowsqueak 5 September 2012 в 22:05

Поскольку вы храните массив в стеке. Вы должны хранить его в куче. См. эту ссылку , чтобы понять концепцию кучи и стека.

2
ответ дан evotopid 21 August 2018 в 07:50
поделиться

Ваш массив выделяется в стеке, в этом случае попытайтесь выделить массив того же размера с помощью alloc.

2
ответ дан rerun 21 August 2018 в 07:50
поделиться

Кроме того, если вы работаете в большинстве UNIX & amp; Linux, вы можете временно увеличить размер стека с помощью следующей команды:

ulimit -s unlimited

Но будьте осторожны, память - это ограниченный ресурс и с большой силой приходят большие обязанности:)

7
ответ дан Usman.3D 21 August 2018 в 07:50
поделиться
  • 1
    Это решение, но я рекомендую всем быть предельно осторожным при удалении этих ограничений по умолчанию для размера стека программы. Вы испытаете не только серьезное падение производительности, но и ваша система может потерпеть крах. Например, я попытался отсортировать массив с 16 000 000 целых элементов с быстрой сортировкой на машине с 4 ГБ оперативной памяти, и моя система была почти убита. лол – rbaleksandar 16 October 2014 в 17:51
  • 2
    @rbaleksandar Я думаю, что вы ~ 16 МБ-программа почти убили вашу машину, потому что вы работали с несколькими копиями массива (может быть один на вызов функции?) попробуйте реализовать более запоминающуюся память;) – RSFalcon7 17 October 2014 в 00:20
  • 3
    Я уверен, что обработка массивов в порядке, поскольку я передаю ссылку, а не по значению. То же самое происходит с bubblesort. Черт, даже если моя реализация quicksort sucks bubblesort - это то, что вы не можете реализовать неправильно. лол – rbaleksandar 17 October 2014 в 11:07
  • 4
    LOL вы можете попробовать отсортировать сортировку или просто использовать std :: sort :) – RSFalcon7 17 October 2014 в 17:54
  • 5
    Без шансов. Это лабораторное задание. : D – rbaleksandar 17 October 2014 в 18:00
Другие вопросы по тегам:

Похожие вопросы: