【问题标题】:Maximum Array Size最大数组大小
【发布时间】:2012-11-13 11:26:47
【问题描述】:

我有以下进行递归合并排序的 arduino 代码。我们必须确定如何计算您可以在此 8192B SRAM 中输入的最大数组元素数量。数组元素个数在这个void setup()中设置

int16_t Test_len = 64;

我很想自己解决这个问题,但下班后毫无希望,我错过了这个讲座,因为我得了流感。

整个代码的副本。

#include <Arduino.h>
#include <mem_syms.h>

// some formatting routines to indent our messages to make it easier
// to trace the recursion.

uint8_t indent_pos = 0;
const uint8_t indent_amt = 2;

void indent_in() {
    if ( indent_pos <= 32 ) {
        indent_pos ++;
        }
    }

void indent_out() {
    if ( indent_pos >= indent_amt ) {
        indent_pos --;
        }
    }

void indent() {
    for (uint8_t i=0; i < indent_pos * indent_amt; i++) {
        Serial.print(" ");
        }
    }

// print out memory use info, s is a simple descriptive string
void mem_info(char *s) {
    indent();
    Serial.print(s);
    Serial.print(" Stack: ");
    Serial.print(STACK_SIZE);
    Serial.print(" Heap: ");
    Serial.print(HEAP_SIZE);
    Serial.print(" Avail: ");
    Serial.print(AVAIL_MEM);
    Serial.println();
    }

// call this after a malloc to confirm that the malloc worked, and 
// if not, display the message s and enter a hard loop

void assert_malloc_ok(void * mem_ptr, char *s) {
    if ( ! mem_ptr ) { 
        Serial.print("Malloc failed. ");
        Serial.print(s);
        Serial.println();
        while ( 1 ) { }
        }
    }

// call this on entry to a procedure to assue that at least required amt of
// memory is available in the free area between stack and heap if not, display
// the message s and enter a hard loop

void assert_free_mem_ok(uint16_t required_amt, char *s) {

    if ( AVAIL_MEM < required_amt ) { 
        Serial.print("Insufficient Free Memory: ");
        Serial.print(s);
        Serial.print(" require ");
        Serial.print(required_amt);
        Serial.print(", have ");
        Serial.print(AVAIL_MEM);
        Serial.println();
        while ( 1 ) { }
        }
    }

void merge(int16_t *Left, int16_t Left_len, int16_t *Right, int16_t Right_len, 
    int16_t *S) {

    // position of next element to be processed
    int Left_pos = 0;
    int Right_pos = 0;

    // position of next element of S to be specified
    // note: S_pos = Left_pos+Right_pos
    int S_pos = 0;

    // false, take from right, true take from left
    int pick_from_left = 0;

    while ( S_pos < Left_len + Right_len ) {

    // pick the smallest element at the head of the lists
    // move smallest of Left[Left_pos] and Right[Right_pos] to S[S_pos] 
    if ( Left_pos >= Left_len ) {
        pick_from_left = 0;
        }
    else if ( Right_pos >= Right_len ) {
        pick_from_left = 1;
        }
    else if ( Left[Left_pos] <= Right[Right_pos] ) {
        pick_from_left = 1;
        }
    else {
        pick_from_left = 0;
        }

    if ( pick_from_left ) {
        S[S_pos] = Left[Left_pos];
        Left_pos++;
        S_pos++;
        }
    else {
        S[S_pos] = Right[Right_pos];
        Right_pos++;
        S_pos++;
        }

    }
}


// sort in place, i.e. A will be reordered
void merge_sort(int16_t *A, int16_t A_len) {
    indent_in();
    indent();
    Serial.print("Entering merge sort: array addr ");
    Serial.print( (int) A );
    Serial.print(" len ");
    Serial.println( A_len);
    mem_info("");

    assert_free_mem_ok(128, "merge_sort");

    if ( A_len < 2 ) {
        indent_out();
        return;
        }

    if ( A_len == 2 ) {
        if ( A[0] > A[1] ) {
            int temp = A[0];
            A[0] = A[1];
            A[1] = temp;
            }
        indent_out();
        return;
        }

    // split A in half, sort left, sort right, then merge
    // left half is:  A[0], ..., A[split_point-1]
    // right half is: A[split_point], ..., A[A_len-1]

    int split_point = A_len / 2;

    indent();
    Serial.println("Doing left sort");

    merge_sort(A, split_point);

    mem_info("After left sort");

    indent();
    Serial.println("Doing right sort");

    merge_sort(A+split_point, A_len-split_point);

    mem_info("After right sort");

    // don't need the merging array S until this point
    int *S = (int *) malloc( A_len * sizeof(int) );// source of 10 bytes accumulation in heap

    assert_malloc_ok(S, "Cannot get merge buffer");

    mem_info("Doing merge");

    merge(A, split_point, A+split_point, A_len-split_point, S);

    for (int i=0; i < A_len; i++) {
        A[i] = S[i];
        }

    // now we are done with it
    free(S);

    mem_info("After free");
    indent_out();
    }

void setup() {
  Serial.begin(9600);

    // int *bad_news = (int *) malloc(4000);

    mem_info("********* THIS IS THE BEGINNING *********");
    randomSeed(analogRead(0));

    int16_t Test_len = 64;
    int16_t Test[Test_len];

    Serial.print("In: ");
    for (int16_t i=0; i < Test_len; i++) {
        Test[i] = random(0, 100);
if ( 1 ) {
        Serial.print(Test[i]);
        Serial.print(" ");
}
        }
    Serial.println();

    merge_sort(Test, Test_len);

if ( 1 ) {
    Serial.print("Out: ");
    for (int16_t i=0; i < Test_len; i++) {
        if ( i < Test_len-1 && Test[i] > Test[i+1] ) {
            Serial.print("Out of order!!");
            }

        Serial.print(Test[i]);
        Serial.print(" ");
        }
    Serial.println();
}
    }

void loop() {
    }

【问题讨论】:

  • 请具体说明您的问题。您提供的代码中是否有错误?如果是,请提供详细信息。您是否要求填补代码中的空白?在自己解决这个问题方面,您尝试过/想到了什么?
  • element_t 类型的元素可以放在 8192 字节的 RAM 中的数量是 8192 / sizeof( element_t )。如果这不能回答您的问题,请在您的问题中更具体。

标签: c++ memory recursion computer-science memory-mapped-files


【解决方案1】:

递归几乎是一条红鲱鱼,最大输入数组大小等于:-

(total_memory - memory_allocated_for_other_stuff) / (2 * number_of_elements * sizeof array_element)

其中total_memory是系统拥有的内存量,memory_allocated_for_other_stuff是程序使用的内存(如果它使用相同的内存),堆栈和其他数据,number_of_elements是数组长度和@ 987654324@ 是要排序的每个元素的字节数。

它是2 * number_of_elements 的原因是您需要分配一个临时缓冲区来将两半合并到您的代码中的SS 的上限等于自每个递归级别以来要排序的数组大小、S 一半所需的大小以及临时缓冲区仅在递归发生后分配。

我说递归性质几乎是一个红鲱鱼,因为S 所需的空间将每个递归步骤减半,所以如果你有内存来做最顶层的合并,那么就足够做所有的递归合并了也是。但是,每个递归步骤都会向堆栈添加固定数量(假设堆栈使用与数据相同的内存),因此memory_allocated_for_other_stuff 随着递归调用的数量线性增加,即堆栈的内存是:-

stack_used = stack_frame_size * (log2(元素数) + 1)

其中stack_frame_size 是创建堆栈帧所需的内存(堆栈上用于保存函数的返回地址、局部变量等的位)。问题是:stack_used 能否超过S 所需的最大空间。答案取决于堆栈帧的大小。使用电子表格,这似乎不是一个容易回答的问题 - 它取决于要排序的数组的大小和堆栈帧的大小,尽管堆栈帧似乎需要相当大才能引起问题。

事实证明,决定您可以排序的最大数组大小的因素之一就是您要排序的数组的大小!

或者,您可以只猜测一个值并查看它是否有效,使用二进制搜索缩小到特定值。

【讨论】:

    猜你喜欢
    • 2012-04-06
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2011-09-03
    • 2011-01-20
    • 2015-11-26
    相关资源
    最近更新 更多