How to Subtract a Constant Value from All Elements of an Array

How to subtract a constant value from all elements of an array?

With streams you can use map like this :

int[] array = {-1, 8, 9};
array = Arrays.stream(array)
.map(i -> i - 7)
.toArray();

or if you are using List you can use :

List<Integer> array = new ArrayList<>(Arrays.asList(-1, 8, 9));
array = array.stream()
.map(i -> i - 7)
.collect(Collectors.toList());

Subtracting a number from all elements of an array in constant time

You can't change n elements in memory in less than O(n) time, but you can change what that memory represents. If you were to create a custom array class you can include an offset member. When an array element is read you add the offset on demand. When an element is added, you subtract the current offset before storing it in memory (so it is recalled as the correct value when added with the offset). With that layout simply modify the offset in O(1) time and effectively achieve what you are looking for.

How to subtract every element from one array to another?

There's really no avoiding having to loop over the arrays at least once, but there is the built-in LINQ Zip method which does most of the hard work for you.

The thing to NOT do is loop more than necessary so dont subtract the constant value after doing the initial subraction - do it at the same time

var array1 = new[]{1, 2, 3, 4, 5, 6};
var array2 = new[]{0.1, 0.2, 0.3, 0.4, 0.5, 0.6};
var constant = 5;
var array3 = array1.Zip(array2, (x,y) => x-y-constant).ToArray();

Live example: https://dotnetfiddle.net/An8IuE

This will ultimately be a little slower than a simple for loop

var array1 = new[]{1, 2, 3, 4, 5, 6};
var array2 = new[]{0.1, 0.2, 0.3, 0.4, 0.5, 0.6};
var constant = 5;
var array3 = new double[array1.Length];
for(int i=0,j=array1.Length; i<j;i++)
array3[i] = array1[i] - array2[i] - constant;

Live example: https://dotnetfiddle.net/r5JQKN

How to subtract an element of an array from every element in another array in Fortran?

I think the comments allude to this well -- you're referencing a 1X1 array element which fortran does not understand as a scalar, though effectively it is. Agentp provides one option for confronting this,

    z_m_z_x = X - sum(zeta_list(1,:))

I usually do something similar, different really only in a semantic manner from agentp's suggestion

    z_m_z_x= X(i,1) - maxval(zetalist(1,:))

In each case you're transforming the array to a scalar via 1) summing all the elements in the array, which is only 1 or 2) picking the maxvalue of all the elements in the array, which again is the max of only 1 value. Minval would work equally well. However, if I understand your question right --- that you have a M x 2 array 'X' that you are trying to subtract out of the values from the first column of zeta_list ---

then there might be a way to vectorize this operation. If you were trying to subtract from X the values of the first column of a 2 X M array, and the arrays both had M rows, then you could simply

    X(:,1)=X(:,1) - zetalist(:,1)
X(:,2)=X(:,2) - zetalist(:,1)

However, this approach will only work if the arrays are of the same number of rows- a specific range would require slicing to an equivalent number of rows in each array as well as the slicing to the right columns. If you are trying to subtract the 1,1 array element from every location in X and you want to use the loop then you could write

   DO i=1,M 
X(i,1) = X(i,1)- zetalist(1,1)
X(i,2) = X(i,2)- zetalist(1,1)
end DO

How to subtract a constant from a numpy array and then summing up the results?

np.sum(an_array)-constant*an_array.size

Edit 1:

I am a few seconds late as @Qui already pointed this solution out in the comments.

Subtract or add constant to large array

You can just write a function with a plain loop:

void add(uint8_t* a, size_t a_len, uint8_t b) {
for(uint8_t* ae = a + a_len; a < ae; ++a)
*a += b;
}

And hope that the compiler vectorizes that for you, which it does, see assembly.

Solutions with std::for_each and std::transform such as:

void add(uint8_t* a, size_t a_len, uint8_t b) {
std::transform(a, a + a_len, a, [b](auto value) { return value + b; });
}

Should generate exactly the same code, but sometimes they don't.


[Updated]

Out of curiosity, I benchmarked the following solutions:

#include <benchmark/benchmark.h>

#include <cstdint>
#include <array>
#include <algorithm>

#include <immintrin.h>

constexpr size_t SIZE = 1824 * 942;
alignas(32) std::array<uint8_t, SIZE> A;

__attribute__((noinline)) void add_loop(uint8_t* a, size_t a_len, uint8_t b) {
for(uint8_t* ae = a + a_len; a < ae; ++a)
*a += b;
}

__attribute__((noinline)) void add_loop_4way(uint8_t* a, size_t a_len, uint8_t b) {
a_len /= 4;
for(uint8_t* ae = a + a_len; a < ae; ++a) {
a[a_len * 0] += b;
a[a_len * 1] += b;
a[a_len * 2] += b;
a[a_len * 3] += b;
}
}

__attribute__((noinline)) void add_transform(uint8_t* a, size_t a_len, uint8_t b) {
std::transform(a, a + a_len, a, [b](auto value) { return value + b; });
}

inline void add_sse_(__m128i* sse_a, size_t a_len, uint8_t b) {
__m128i sse_b = _mm_set1_epi8(b);
for(__m128i* ae = sse_a + a_len / (sizeof *sse_a / sizeof b); sse_a < ae; ++sse_a)
*sse_a = _mm_add_epi8(*sse_a, sse_b);
}

__attribute__((noinline)) void add_sse(uint8_t* a, size_t a_len, uint8_t b) {
add_sse_(reinterpret_cast<__m128i*>(a), a_len, b);
}

inline void add_avx_(__m256i* avx_a, size_t a_len, uint8_t b) {
__m256i avx_b = _mm256_set1_epi8(b);
for(__m256i* ae = avx_a + a_len / (sizeof *avx_a / sizeof b); avx_a < ae; ++avx_a)
*avx_a = _mm256_add_epi8(*avx_a, avx_b);
}

__attribute__((noinline)) void add_avx(uint8_t* a, size_t a_len, uint8_t b) {
add_avx_(reinterpret_cast<__m256i*>(a), a_len, b);
}

template<decltype(&add_loop) F>
void B(benchmark::State& state) {
for(auto _ : state)
F(A.data(), A.size(), 15);
}

BENCHMARK_TEMPLATE(B, add_loop);
BENCHMARK_TEMPLATE(B, add_loop_4way);
BENCHMARK_TEMPLATE(B, add_transform);
BENCHMARK_TEMPLATE(B, add_sse);
BENCHMARK_TEMPLATE(B, add_avx);

BENCHMARK_MAIN();

Results on i7-7700k CPU and g++-8.3 -DNDEBUG -O3 -march=native -mtune=native:

------------------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------------------
B<add_loop> 31589 ns 31589 ns 21981
B<add_loop_4way> 30030 ns 30030 ns 23265
B<add_transform> 31590 ns 31589 ns 22159
B<add_sse> 39993 ns 39992 ns 17403
B<add_avx> 31588 ns 31587 ns 22161

Times for loop, transform and AVX2 versions are pretty much identical.

SSE version is slower because the compiler generates faster AVX2 code.

perf report reports ~50% L1d-cache miss rate which indicates that the algorithm is bottlenecked by memory access. Modern CPUs can handle multiple memory accesses simultaneously, so that you can squeeze an extra ~5% of performance here by accessing 4 regions of memory in parallel, which is what the 4-way loop does (for your particular array size 4 ways is the fastest). See Memory-level parallelism: Intel Skylake versus Intel Cannonlake for more details.

I need to subtract value from the array

Your best bet is a for loop.
This will allow you to perform an action (I.E subtraction) on each 'element' of an array.
By using a return statement, you can return the new array that has had each element modified

EDIT As per @AlexeiLevenkov's comment, I have updated my answer to keep a count of the remaining subtraction.
Using this to test :

using System;

public class Program
{
public static void Main()
{
int[] array = new int[]{5,10,15,20,25,30,35};
array=SubtractArray(array,25);
Console.WriteLine("Output is:");
foreach(int v in array){
Console.WriteLine(v+", ");
}
}
public static int[] SubtractArray(int[] array , int subtraction){
for(int i=0; i< array.Length;i++){
if(subtraction>0){
int newValue=array[i]-subtraction;
if(newValue<1){
newValue=0;
subtraction=subtraction-array[i];
}
array[i]=newValue;
}
}
return array;
}
}


Related Topics



Leave a reply



Submit