2013-08-09 3 views
2

Мне задан массив из N элементов, и мне нужно найти индекс P в этом массиве, где сумма значений в диапазоне от 0 до P равна сумме значений в диапазоне P + 1 к N-1.Обработка больших чисел и переполнения

значения каждого элемента массива может варьироваться в -2147483648 до 2147483647 и N может быть не более 10000000.

Учитывая это, как я гарантировать не переполнение при добавлении каждой значения, чтобы найти индекс P ?

+3

Похоже 'длинной long' должно хватить. –

+0

@ jerry-coffin Обратите внимание на использование слова ** обеспечить ** в вопросе в самом конце, «обеспечить» обычно не считается эквивалентным _should_. – mctylr

+0

@mctylr: Я бы не стал упоминать об этом, если это было недостаточно, но: «' long long' * гарантирует * достаточный диапазон ». Это делает вас счастливее? –

ответ

4

Чтобы избежать переполнения, используйте int32_t и int64_t.

Диапазон значений [-2147483648 ... 2147483647] соответствует диапазону int32_t. Вы также можете использовать для этого int64_t, но массив из 10000000 заслуживает внимания пространства.

Поскольку сумма любых 10000000 значений не превышает диапазон int64_t, выполнять все ваши дополнения, используя int64_t.

#include <stdint.h> 
size_t foo(const int32_t *value, size_t N) { 
    int64_t sum = 0; 
    ... 
    sum += value[i]; 
    ... 
} 

Кстати: Уверенный, что решение можно было, что не требует добавления 64-битного сложения.
[Редактировать] Не удалось получить простое int32_t единственное решение, но придумал:

size_t HalfSum(const int32_t *value, size_t N) { 
    // find sum of entire array  
    int64_t ArraySum = 0; 
    size_t P; 
    for (P = 0; P < N; P++) { 
    ArraySum += value[P]; 
    } 

    // compute sum again, stopping when it is half of total 
    int64_t PartialSum = 0; 
    for (P = 0; P < N; P++) { 
    PartialSum += value[P]; 
    if ((PartialSum * 2) == ArraySum) { 
     return P; 
    } 
    } 

    return N; // No solution (normally P should be 0 ... N-1) 
} 
+1

Или немного математике:! [Sum_ {n} = \ sum_ {i = 0}^{N} p_ {i} \, \ text {where} \, p_ {i} \ in \ mathbf {P} = [-2147483648, 2147483647] \, \ text {и} \, N \ leq 10000000 ] (http://mathurl.com/lay9okj), тогда нетрудно что max (сумма n) составляет 10000000 * 2147483647 = 21474836470000000 или '0x004C 4B3F FF67 6980', поэтому он исправляет внутри' int64_t' из 'stdint.h' – mctylr

+1

@ mctylr Я подозреваю, что причина для 10000000 - исключить использование «двойной». (53 бит + знак) – chux

+0

@mctylr ;-) Незначительная точка выдумки: ваша математика проверила только _one_ конца диапазона. Минимум 10000000 * -2147483648, который, как ваш максимум, требует 53 бит и знак. – chux

-1

В худшем случае P + 1 = N-1. Поскольку максимальное значение ynumber может быть только 2147483647 или -2147483647 для любого единственного числа, это означает, что в наихудших случаях P будет максимальным или минимальным. В других случаях P все равно будет длинным целым числом. Из-за этого вам нужно использовать только длинный сценарий наихудшего случая (поскольку, если в худшем случае ожидаемый результат будет таким, что P является самым большим возможным числом, которое может быть любым одним числом, оно является длинным.

Чтобы убедиться, что вам не нужно использовать ничего большего, сопоставьте отрицательные значения с постовыми, чтобы вы оставались ниже переполнения длинного.

Представьте, что у нас есть 3 числа, ab и C. Если a + b переполняет длинный тип данных , мы знаем, что c не будет P.

Теперь представьте, что у нас есть 4 числа, a, b, c, d такие, что a + b + c = d (означает d является P), если a + b будет overflow long, это означает 1) c не может быть P 2) существует комбинация a + b + c, так что тип данных long не должен быть переполнен.

Например, a является максимально длинным, b является максимальным, c является минимальным, а d равно 0, то a + c + b = d будет правильной комбинацией операций, чтобы не использовать тип данных больше, чем длинный, и мы можем попробовать + c, так как мы знаем, что c не может быть P, так как a + b будет переполняться длинным> максимально возможное значение P.

+1

Я думаю, что это неправильно, если первые два значения равны 2147483647, когда вы добавляете их, вы получаете переполнение, если используете длинный. – Marichyasana

+0

@Marichyasana: ты прочитал последнюю часть? Если у вас есть два числа, которые переполняются дольше, вы не добавляете их, поскольку вы знаете, что элементы 1 + 2> допустимые значения P, поэтому вы знаете, что P не может быть следующим элементом. Таким образом, в будущем должны быть значения, которые приведут к тому, что это число будет ниже точки переполнения, и, таким образом, вы можете связать его с отрицательным числом в будущем, чтобы отрицать любой эффект переполнения от двух чисел. Перестаньте думать так серийно, это глупый способ думать. – Magn3s1um

+1

@ Magn3s1um Нет причин полагать, что наступают отрицательные числа, которые приведут к приближению текущей суммы к нулю. И я думаю, вы неправильно поняли этот вопрос. На сумму, которая может быть достигнута, не указано ограничение. Сумма нижнего раздела массива, эквивалентная сумме верхнего раздела, может быть очень большим числом, которое переполняет 32 бита много раз многократно. Все значения в массиве могут быть большими положительными целыми числами. – Kaz

1

Используйте 64-битные целые числа для ваших вычислений. Лучшим типом для использования является int64_t, так как long не гарантированно будет 64 бита (у вас должно быть #include <stdint.h>, чтобы сделать его доступным).

Edit: Паскаль Cuoq прав: long long действительно обеспечивает 64-битную гарантию, а также и не нуждается в включаемой (он может быть длиннее, чем 64 бита, хотя), так что это просто тип long, что вы должны избегайте, если вы хотите быть портативным.

+0

stdint.h был введен в C99, который в то же время представил 'long long', который, как гарантируется, должен быть не менее 64-битным, не требует заголовка и не является необязательным в том, как типы в stdint.h находятся. –

+0

@PascalCuoq: Я не знал об этой гарантии, но я рад, что она там. Спасибо за то, что указали это :-) – cmaster

Смежные вопросы