Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dynamic type

65 views
Skip to first unread message

Cristiano

unread,
Jul 4, 2016, 7:41:42 AM7/4/16
to
Header file:

//typedef double TIPO;
typedef float TIPO;

struct COEFF {
TIPO *c[6];
};

struct COEFF *coe;


cpp file:

for(int i= 0; i < 3; i++) {
coe[I].c[i]= new TIPO[ncoe];
if(fread(coe[I].c[i], sizeof(TIPO), ncoe, f) != ncoe) {
puts("ERROR"); return 3;
}
}

const TIPO **c= (const TIPO **)coe[idx].c;

Is there any memory efficient way to rewrite the code to switch from
float to double at runtime?

Thank you
Cristiano

Paavo Helde

unread,
Jul 4, 2016, 9:04:01 AM7/4/16
to
Not sure what kind of memory efficiency do you have in mind. Double
takes twice as much space as a float, so you will definitely lose memory
when switching to double.

For supporting both float and double by the same code, make it templated.

For storing both floats and doubles in the same array - forget about the
idea.

For reading in floats from a binary non-portable file and store them in
a double array just read them one-by-one and store in a double array.

Also note that your code resembles more C than C++ and as a result it is
leaking memory (at least if an error occurs). The only C++ feature in
the code ('new') should not appear at all in such code, std::vector
should be preferred for most usage cases.

HTH
Paavo








Cristiano

unread,
Jul 4, 2016, 9:26:25 AM7/4/16
to
On 04/07/2016 15:03, Paavo Helde wrote:
> On 4.07.2016 14:41, Cristiano wrote:
>> Header file:
>>
>> //typedef double TIPO;
>> typedef float TIPO;
>>
>> struct COEFF {
>> TIPO *c[6];
>> };
>>
>> struct COEFF *coe;
>>
>>
>> cpp file:
>>
>> for(int i= 0; i < 3; i++) {
>> coe[I].c[i]= new TIPO[ncoe];
>> if(fread(coe[I].c[i], sizeof(TIPO), ncoe, f) != ncoe) {
>> puts("ERROR"); return 3;
>> }
>> }
>>
>> const TIPO **c= (const TIPO **)coe[idx].c;
>>
>> Is there any memory efficient way to rewrite the code to switch from
>> float to double at runtime?
>
> Not sure what kind of memory efficiency do you have in mind. Double
> takes twice as much space as a float, so you will definitely lose memory
> when switching to double.
>
> For supporting both float and double by the same code, make it templated.

That is the case.
As you noticed, my C++ programming skill is not good (like my English
:-)); please, would you post an example?

Cristiano

Öö Tiib

unread,
Jul 4, 2016, 10:18:01 AM7/4/16
to
On Monday, 4 July 2016 14:41:42 UTC+3, Cristiano wrote:
> Header file:

Looks like short C header (but without multiple inclusion
guards).

>
> //typedef double TIPO;
> typedef float TIPO;
>
> struct COEFF {
> TIPO *c[6];
> };
>
> struct COEFF *coe;

The keyword 'struct' is redundant in global variable 'coe'
declaration.

>
> cpp file:
>
> for(int i= 0; i < 3; i++) {
> coe[I].c[i]= new TIPO[ncoe];
> if(fread(coe[I].c[i], sizeof(TIPO), ncoe, f) != ncoe) {
> puts("ERROR"); return 3;
> }
> }
>
> const TIPO **c= (const TIPO **)coe[idx].c;

That can not compile. You can not write 'for' cycles directly
into global namespace, you have to put those inside of
functions.

> Is there any memory efficient way to rewrite the code to switch from
> float to double at runtime?

Achieve that the code compiles, then that it does what you want,
then that it does it always and accurately. Only then think how
can you achieve efficiency. It is because no one cares how fastly
and efficiently a program gives wrong answers.

Paavo Helde

unread,
Jul 4, 2016, 1:03:15 PM7/4/16
to
Some more or less pseudocode, might give you some ideas. The main point
is that at some point you need explicit runtime dispatch to templates
(here done inside main()).

template<typename TIPO>
class COEFF {
std::vector<TIPO> c[6];

public:
void Read(std::istream& f);
for(int i= 0; i < 3; i++) {
c[i].resize(ncoe);
if(!f.read(c[i].data(), sizeof(TIPO)*ncoe) {
throw std::runtime_error("ERROR");
}
}
}
// ...
};

// cpp file:

template<typename TIPO>
void DoWork() {
std::vector<COEFF<TIPO>> coe(N);
for (int I=0; I<N; ++I) {
std::ifstream f(filename, std::ios::binary);
coe[I].Read(f);
}
// ...
}


int main() {
try {

// ...
if (useFloat> {
DoWork<float>();
} else {
DoWork<double>();
}

} catch(const std::exception& e) {
std::cerr << e.what() << "\n";
return EXIT_FAILURE;
}
}



Barry Schwarz

unread,
Jul 4, 2016, 2:54:50 PM7/4/16
to
On Mon, 04 Jul 2016 15:26:19 +0200, Cristiano <cris...@NSgmail.com>
wrote:
While templates can support multiple types, the decision about which
type is determined at compile time, not run time.

--
Remove del for email

Paavo Helde

unread,
Jul 4, 2016, 3:31:51 PM7/4/16
to
Yes, that's why there is an explicit runtime dispatch needed. In one
branch of the dispatch one type is determined at compile time, in
another branch another, etc.

In our codebase we have macros which dispatch ca 10 types to a templated
function. That's one remaining usage case for macros in C++.

Cheers




Cristiano

unread,
Jul 4, 2016, 3:52:00 PM7/4/16
to
[...]

It seems that I need to completely rewrite my code.
Unfortunately, the code is for a DLL that will be used in a program not
written by me and I cannot use all your code, but I got the point.

Thanks a lot
Cristiano

Cristiano

unread,
Jul 4, 2016, 7:44:46 PM7/4/16
to
On 04/07/2016 19:03, Paavo Helde wrote:
> template<typename TIPO>
> class COEFF {
> std::vector<TIPO> c[6];
[...]

Thank to your help, I wrote a working version of my code, but since I
need to call several functions like:

if (useFloat) DoWork_1<float>();
else DoWork_1<double>();
...
if (useFloat) DoWork_2<float>();
else DoWork_2<double>();
...

is there any way to set <float> or <double> once and for all and then
simply call DoWork_1(), DoWork_2(), ... ?

Cristiano

Christian Gollwitzer

unread,
Jul 5, 2016, 2:38:10 AM7/5/16
to
Am 05.07.16 um 01:44 schrieb Cristiano:
You cannot set it like a global switch. Think like a compiler: the
compiler has to generate completely different code, therefore you must
pass that information around at compile time. However, you need such a
switch only once. You can "pass" the type as a template parameter either
explicitly or implicitly:

template <typename T> void Subtask1 (T x) { }
template <typename T> void Subtask2 (T x) { }
template <typename T> void Subtask3 () { }

template <typename T> void MyMain () {

T f = 0;
Subtask1(f);
Subtask2(f);
Subtask3<T>();
}

int main() {
if (useFloat) {
MyMain<float>();
} else {
MyMain<double>();
}
}

See? The if switch is only in the main function. All functions then
decide on the type via overload resolution (Subtask1 & Subtask2) or via
an explicit template parameter (Subtask3), in case if there is no
argument where the compiler gets the type from.

Christian

Paavo Helde

unread,
Jul 5, 2016, 2:38:30 AM7/5/16
to
Yes, you can use a virtual interface:

#include <memory>

class Base {
public:
virtual void DoWork1() = 0;
virtual void DoWork2() = 0;
};

template<class TIPO>
class COEFF: public Base {
virtual void DoWork1() override { /*...*/ }
virtual void DoWork2() override { /*...*/ }
};

int main() {
bool useDouble = (rand()%2==0);

std::unique_ptr<Base> p;
if (useDouble) {
p.reset(new COEFF<float>());
} else {
p.reset(new COEFF<double>());
}

p->DoWork1();
p->DoWork2();
}



hth
Paavo

Cristiano

unread,
Jul 5, 2016, 5:00:53 PM7/5/16
to
On 05/07/2016 08:38, Paavo Helde wrote:
> On 5.07.2016 2:44, Cristiano wrote:
>> On 04/07/2016 19:03, Paavo Helde wrote:
>>> template<typename TIPO>
>>> class COEFF {
>>> std::vector<TIPO> c[6];
>> [...]
>>
>> Thank to your help, I wrote a working version of my code, but since I
>> need to call several functions like:
>>
>> if (useFloat) DoWork_1<float>();
>> else DoWork_1<double>();
>> ...
>> if (useFloat) DoWork_2<float>();
>> else DoWork_2<double>();
>> ...
>>
>> is there any way to set <float> or <double> once and for all and then
>> simply call DoWork_1(), DoWork_2(), ... ?
>
> Yes, you can use a virtual interface:
[...]

I used your solution because it better fits my original code (I already
use a class).
Thank you very much for your valuable help.

Many thanks also to Christian.

Cristiano


Paavo Helde

unread,
Jul 6, 2016, 11:19:36 AM7/6/16
to
On 5.07.2016 22:00, Cristiano wrote:
> On 05/07/2016 08:38, Paavo Helde wrote:
>>
>> Yes, you can use a virtual interface:
> [...]
>
> I used your solution because it better fits my original code (I already
> use a class).

Just an extra note: I noticed that in my axample of virtual interface I
have failed to define a virtual destructor in the base class, one should
always have that to avoid resource leaks or worse.

Cheers
Paavo




0 new messages