Help with absolute value of an array

Hello, I have some function that inside I am trying to take the absolute value of an array using std::valarray. But I keep getting the errors:

1
2
  no instance of overloaded function "abs" matches the argument lis --argument types are: (double *)
  no suitable conversion function from "stad::valarray<double>" to "double*" exists


My array U is defined as the following:
 
double U[3] = {-10,0,0};


The error showing in the function:
1
2
3
4
5
6
7
8
9
10
11
12
        std::valarray<double> U;
        std::valarray<double> bar = abs(U); // here 

        
        double vMaxArr[7];

        // some calculations 
        vMaxArr[6] = Arr1DMax(bar, 3); // here
        
        double max = Arr1DMax(vMaxArr, 7);
       // some calculations 
        }


Basically, I am asking how to take the absolute value of array U and use it as an input in Arr1DMax which is:
1
2
3
4
5
6
7
8
double Arr1DMax(double arr[], int arrLength){
    double max = 0.0;
    for (int i = 0; i < arrLength; i++){
        if (arr[i] > max){
            max = arr[i];
        }
    }
    return max;
Last edited on
If you try to find the absolute values of a valarray you need to create U as a valarray, not as an array.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <valarray>
#include <iostream>

int main()
{
   std::valarray<double> v { -10.5, 0.7, .0005 };
   std::valarray<double> v2 = std::abs(v);

   for (auto n : v2)
   {
      std::cout << n << ' ';
   }
   std::cout << '\n';
}

In your 3rd code snippet you are creating an empty U valarray.

You can't send a valarray<double> to a function expecting a double []. They are very different types of array.

If you use valarrays then you don't need that function anyway. You could just use
bar.max()
Last edited on
My array U is defined as the following:
No, it's not. std::valarray is not an array.

So why don't you just use an array when you want to?

For what std::valarray is see:

http://www.cplusplus.com/reference/valarray/valarray/?kw=valarray

If you indeed want to use std::valarray turning the values to absolute (line 2) would look like this:

std::valarray<double> bar = U.apply(std::abs);

Copy to an array:

std::copy(std::begin(bar), std::begin(bar) + 7, vMaxArr);
valarray can do some slick stuff, but so far what I see for this task is all syntax sugar to hide a loop that takes abs of all the elements and does whatever with the results. There is nothing wrong with that, but its not necessary either -- you are copying U for no real reason, allocating memory for no real reason (valarray does it for you, hidden), and so on. Pick a container and use it, and if you have to do an occasional loop yourself (or use transform to hide it) so be it (if you choose a C array type thing) or go ahead and use valarray from the the onset (probably the better way).
Last edited on
Okay, so I then completely misunderstood the idea behind std::valarray, I thought it was an array. So, this is just a function in the main code I do define U array there and I am trying to use it as a variable that I can change for different results. All I wanted to do is just take the absolute value, and I saw that abs(x) is not used for arrays so I went with std::valarray.

I am getting confused really on how to find an absolute value of an array, do I just simply do a for loop?
I had this simple for loop that is not quiet working (results are flipped in the negative direction), so what is the problem really?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int N = 3;
        for (int i=0; i < N; i++){
            if (U[i] < 0){
                //absArr[i] = U[i] * (-1);
                U[i] = U[i] * (-1);
              

            }
        }
        //print2DPhysArray(absArr);

        double vMaxArr[7];
      // some calculations
        vMaxArr[6] = Arr1DMax(U,3); /
I'd just recode it in Fortran: you'll find it much easier for numeric arrays:
U = [-10.0, 2 * 0.0 ]
vMaxArr = maxval( abs( U ) )
just say this:

for (int i=0; i < N; i++)
{
U[i] = abs(U[i]);
}

the fancy way: (here, if U is a container, the begin and end, if it is an array, you can use pointers)
std::transform(U.begin(), U.end(),U.begin(), ::abs);
this is almost exactly the same as the for loop, when it compiles, the for loop may have an extra register in use or something minor.

your loop looks correct, assuming U is actually signed type, but its way overkill. A condition costs you as much effort as the work you bypassed here, so that is just code bloat. Given that your code looks correct in that loop, you may have a bug elsewhere that messes up the sign.

valarray, vector, std::array, and C arrays (int x[10] type) are all 'arrays' sort of. Or another way to say it, the first 3 are objects that wrap the 'concept' of an array like container into an object oriented tool with many extra features. you can use ANY of them for this, and the choice depends on what you want to do. Valarray is really good at certain types of number crunching, vectors are more generic data dump containers that just hold the data in cells, std:array is just enough object to remove the aggravations of C arrays, and C arrays are just memory locations, really.
Last edited on
Thanks everyone! This was very helpful.
Registered users can post here. Sign in or register to post.