condensing similar overloaded functions

Is there a nice way to reduce the pseudo code below into just one function? This code must be very fast (we are using SIMD, intrinsics, multi-core etc).

Right now it is done as an overload with two functions and works fine and efficient but it is redundant and klunky to maintain.
I "could" reduce this to use the single function listed but this causes the "if" statement to be issued over and over again and efficiency is at a premium here.
There probably is a "nice" C++ way to do this but I am not sure?

Thanks
Fritz

///////////// Overloading 2 separate functions ///////////////////
int func1(Matrix &Output)
{
for(idx very-large-loop...)
{
[lots of code]
Output.datao[idx] = blah-blah;
}
return 0
}

int func1(Matrix &Output)
{
for(idx very-large-loop...)
{
[lots of code]
datao[idx] = blah-blah;
}
return 0
}

/////// Reduced to 1 function with "if" ///////////////////////////////////
int func(Matrix &Output)
{
for(idx very-large-loop...)
{
[lots of code]
if (&Output == NULL)
datao[idx] = blah-blah;
else
Output.datao[idx] = blah-blah;
}
return 0
}
Can you do it less pseudo, because I can't see difference in these:
1
2
int func1(Matrix&);
int func1(Matrix&);


The datao jumps out of nowhere.

And how does address of Matrix object compare to macro NULL?
1
2
3
int func(Matrix &Output)
{
   &Output == NULL
Sorry--I copied wrong. Below is what I intended with func1(&Output) being an overload of func1().
datao is just a variable defined in the class that the function is associated with.
And i think I have seen the "NULL" reference before in regards to an undefined parameter.
Fritz

///////////// Overloading 2 separate functions ///////////////////
int func1(Matrix &Output)
{
for(idx very-large-loop...)
{
[lots of code]
Output.datao[idx] = blah-blah;
}
return 0
}

int func1()
{
for(idx very-large-loop...)
{
[lots of code]
datao[idx] = blah-blah;
}
return 0
}

/////// Reduced to 1 function with "if" ///////////////////////////////////
int func(Matrix &Output)
{
for(idx very-large-loop...)
{
[lots of code]
if (&Output == NULL)
datao[idx] = blah-blah;
else
Output.datao[idx] = blah-blah;
}
return 0
}
oh. I see.
um
int func1(matrix * m = nullptr)
{
if(m) ///use m somehow
else /// do whatever you do without the m
}

depending on your matrix object ... if it can be 'empty' (eg 0 for rows and cols) or something, you can use that idea instead of a pointer -- let the default be an empty/constructed object and override by passing something in
Last edited on
Thanks.
Yes-that would work-but I guess the it would keep recurring in the loop-that uses cycles. (we may call a 50x50 matrix many times/sec)

Perhaps it just needs to be coded separately for efficiency coding. I note a lot of things I was used to in the past go away when we are counting nano-secs. Even how I address the loops makes a huge difference (row,col) vs (col,row) vs pointer and so on

Fritz
Yes. If you can stand it, doing them in 1-D is very efficient for many operations.
Don't reinvent the wheel. There are several high performance matrix libraries out there, for free. These usually have good numerical methods and algorithms and threading etc that would take forever to recreate at that quality level. If your matrices are friendly, like for controls of stable systems, you can dodge some of the numerical stuff and just do the work, sometimes saving a fair bit of work, but I don't know if that is worth it anymore (I was doing this stuff pre pentium era, so I did write my own, and it was fast, but today you have far better options than I did).
Thanks for the comment. I am not in charge of this project but the code needs to be "in house" for a lot of reasons beyond me. That doesn't keep me from looking to the side at the work of others though. But I think the staff knows that this is a lifetime specialty and not within the scope of the usual US research project cost and time.

As you say-more has gone into this type of thing over the last 50 years than I can imagine. I grew up on Knuth, UNIVACs and 8-index atomic orbital matrixes. (luckily the present case is 2 indexes). I don't think I could do it again and would certainly look to other sources where I can.
The new processors have some pretty amazing efficiencies that I am absorbing-I think a lot in my area is driven by machine learning and image processing which raises the bar of course. The integration of hardware with processing is interesting-SIMD which uses register sharing seems useful. And for large matrices we can use multiple processors if we can block diagonalize them--

Thanks again
Fritz
Is the usage known at compile time or only at run-time?

If yes, then something like (not tried):

1
2
3
4
5
6
7
8
9
10
11
12
13
template <bool data = true>
int func(Matrix* Output = nullptr)
{
	for (idx very - large - loop...)
	{
		[lots of code]
		if constexpr (data)
			datao[idx] = blah - blah;
		else
			Output.datao[idx] = blah - blah;
	}
	return 0
}


where if constexpr ()is evaluated at compile time so has no run-time performance hit.

How about...

1
2
3
4
5
6
7
8
9
10
int func(Matrix &Output)
{
    Vector& theVector = (&Output == NULL) ? datao : Output.datao;
    for(idx very-large-loop...)
    {
        [lots of code]
        theVector[idx] = blah-blah;
    }
    return 0
} 
1
2
3
int func(Matrix &Output) {
...
if (&Output == NULL)
I'm 99% certain that NULL can never refer to an object and you can't create a reference to it, so this is probably undefined behavior.

To fix this and the original problem, how about:
1
2
3
4
5
6
7
8
9
10
11
int func1(DataoType &datao)
{
    for(idx very-large-loop...) {
        [lots of code]
        datao[idx] = blah-blah;
    }
    return 0
}

int func1() { return func1(datao); }
int func1(Matrix &Output) { return func1(Output.datao); }


Better yet would be to have just the one function func1(DataoType&), and change the callers to call it with the appropriate parameter (datao, or Output.datao)
less than 1% - an overloaded address-of operator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

struct Matrix {

    const Matrix* operator& () const noexcept { return v > 0 ? this : nullptr ; }
    int v = 0 ;
};

int func( Matrix& Output ) {

    if( &Output == NULL ) { std::cout << "nullptr\n" ; return 0 ; }
    else return Output.v ;
}

int main() {

    Matrix mtx{-23} ;
    func(mtx) ;
}
Topic archived. No new replies allowed.