I’ve finally figured out, why I was having so many problems, with complex numbers, in a C++ program.

In This earlier posting, I had written that many things could go wrong, with the way C++ templates define complex numbers. Well, after studying the programming exercise which I was basing that posting on, I think I’ve finally found out, what the single problem in fact was.

In my programming exercise, I had defined the data-type ‘complex<double_t>‘. This in itself caused a lot of problems, without being obvious to me as the culprit. The way C++ templates define complex numbers, will often derive the base-type of one complex number, from the base-type of another, preexisting one, just by transferring a template parameter. However, there are two situations where the templates, defined in the headers, can run into trouble with this:

  1. They can try to convert a ‘real number’ to a complex number, where the base-type of the derived complex number was never declared,
  2. They can try to mix mathematical operations between complex numbers and ‘real numbers’, in such a way that the type of the real number must match the base-type of the complex number exactly.

Specifically in situation (1) above, the templates will try the specializations of ‘float‘, ‘double‘, and ‘long double‘, as educated guesses, for what type of complex number is required. And the problem may well be, that only these 3 template-specializations are attempted, not, ‘double_t’.

And in situation (2) above, I was not taking into consideration that my code was often providing literal numbers, that were of type ‘double‘ by nature, not of type ‘double_t‘. This created a mismatch.

In any case, now that I realize what my mistake was, as well as having removed all the ‘mixed computations, between complex and real numbers’, resulting in code that no longer generates errors, I am more confident that I only was days ago, in the C++ template-definitions, for complex numbers.

 


 

(Update 9/17/2019, 10h50 : )

An added observation would be, that when my code tried to find the absolute, of the real component, of a complex number, that real component was also a ‘double_t‘ (deterministically), but the absolute function that’s predefined, again, only recognizes parameter-types ‘int‘, ‘float‘, ‘double‘, and ‘long double‘, in certain versions of the GCC compiler, which can again result in an incorrect match, with a working version of the absolute function.

Dirk

 

Print Friendly, PDF & Email

What can go wrong, when implementing complex numbers in C++ (Possible Solution).

One of the ideas which exist in computer programming, and with object-oriented languages such as C++, is that a header file can define a ‘complex’ data-type, which has a non-complex base-type, such that the Mathematical definition of Complex Numbers is observed, that define them as:

( a + b i )

Where (a) and (b) are of the base-type, which in pure Math is the set of Real Numbers. According to object-oriented programming, a mere header file can then overload how to perform the standard math operations on these complex objects, based on a super-set of math operations already being defined for the base-type. And the complex object can be defined as a template class, to make that as easy as possible.

Well I have already run in to a programming exercise, where I discovered that the header files that ship with Debian / Stretch (which was finally based on GCC v6.3.0), botched the job. The way in which a bug can begin, is that according to what I just wrote, (a) and (b) could be of the type ‘integer’, just because all the required math operations can be defined to exist entirely for integers, including the ‘integer square root’, which returns an integer even when its parameter is not a perfect square.

This type of complex object makes no sense according to real math, but does according to the compiler.

One of the things which can go wrong with this is, that when creating a special ‘absolute function’, only a complex object could be specified as the possible parameter-type. But, complex objects can have a set of ‘type-conversion constructors’, that accept first an integer, then a single-precision, and then a double-precision floating-point number, and which, depending on which type the parameter can match, convert that single parameter into a temporary complex object, that has this parameter as its real component, and that has zero as its imaginary component, so that the absolute-function-call can be computed on the resulting complex object.

When the compiler resorts to “Standard Conversions” (see first article linked to above), then it is willing to perform conversions between internal types as well as programmer-defined conversions.

If somebody did choose this inefficient way of implementing the absolute function of complex objects, in a way that also computes the absolute of ‘real numbers’, then one trap to avoid would be, only to define a type-conversion constructor, that can initialize the complex object from an integer, and never from a double-precision floating-point number. This first type-conversion to an integer would succeed, and would compute its absolute, resulting in a non-negative integer.

This is obviously totally counter to what a programmer would plausibly want his code to do, but one of the first facts which are taught in Programming Courses, is that compilers will choose non-obvious, incorrect ways to behave, if their code gives them an opportunity to do so.

If the programmer wants to do this deliberately, the conversion to ‘integer’ is referred to as ‘the floor function (of the initial floating-point number)’.

Yet, this type of error seems less likely in the implementation of square roots of complex numbers, that rely on square roots of real numbers, etc.

The correct thing to do is to declare a template function, which accepts the data-type of the parameter as its template variable. And then the programmer would need to write a series of template specializations, in which this template variable matches certain data-types. Only, in the case of the ‘absolute function’ under Debian / Stretch, the implementers seem to have overlooked a template specialization, to compute the absolute of a double-precision floating-point number.

However, actually solving the problem may often not be so easy, because The template-variable could indicate a complex object, which is itself of a template class, with a template variable of its own (that mentioned base-type)

One fact to note about all this is, that there is not one set of headers. There are many versions of headers, each of which ship with a different compiler version. Further, not all people use the GNU compilers; some people use Microsoft’s Visual Studio for example… I just happened to base much of my coding on GCC v6.3.0.

An additional fact to observe is, that the headers to be ‘#include’d are written ‘<complex>’, not, ‘<complex.h>’ . What the missing ‘.h’ means, is that they are “precompiled headers”, which do not contain any text. All this makes verification very difficult. GNU is currently based on GCC v9.2, but I was building my projects, actually using ‘STDC++2014′, which was an available command-line option.

Additionally, when programmers go to Web-sites like this one, the information contained is merely meant as a quick guide, on how to program, using these types of tools, and not an exact match of any code that was ever used to compile my headers.

One way in which I can tell that that code is not literally correct, is by the fact that no version information was provided on the Web-site. Another is by the fact that while the site uses data-types such as “double” and “float”, when programmers compile compilers, they additionally tend to use data-types like ‘double_t’, which will refer to the exact register-size on some FPUs, that may actually be 80-bit. Further, the types ‘int32′ and ‘int64′ would be less ambiguous at the binary level, than the declarations ‘int’ or ‘long int’ would be, if there was ever any explicit support for signed integers… Hence, if my code got ‘complex<double_t>’ to work, but that type was never specified on the site, then the site can just as easily have overlooked the type ‘int64′

According to what I read, C and C++ compilers are intentionally vague about what the difference between ‘double’ and ‘long double’ is, only guaranteeing that ‘long double’ will give at least as much precision as ‘double’. But, If the contents of an 80-bit (floating-point) register are stored in a 64-bit RAM location, then some least-significant bits of the significand are discarded, in addition to the power of two being given a new offset. In order to implement that, the compiler both uses and offers the type, that refers to the exact register-contents, which may be 80 bits or may be 64 bits, for a 64-bit CPU…

(Updated 9/17/2019, 12h10 … )

Continue reading What can go wrong, when implementing complex numbers in C++ (Possible Solution).

Print Friendly, PDF & Email

Technical Impediment In Getting Sound From My Linux Tablet (Solved)

One of the facts which I’ve blogged about is, that I have a Linux Guest System installed on the Android Tablet, that’s a Google Pixel C.

Another fact which I blogged about a long time ago was, that I am able to share the PulseAudio Sound Server that resides on the computer now named ‘Phosphene’, for use by the client computer I name ‘Klexel’.

A basic limitation to my Linux Tablet remains, that it isn’t suited to play back audio streams, or video streams that have audio, because inherently, I’m just running its Linux Guest as a VNC Session. And so a logical thought on that would be:

‘Why not specify the Sound-Providing Server, as the place that the Linux Guest System streams its sound to, at least as long as I am on my own LAN?’

And while in theory this sounds like a good idea, in practice the implementation is still some distance away.

The main problem? While ‘Klexel’ is connected to this Sound Server, it ties up the only TCP Port, which is therefore unable to accept new connections, say from my Linux Tablet. Now, I can tell ‘Klexel’ to relinquish its session on the Sound Server, but doing so has an unexpected consequence. This corrupts the module on the PulseAudio Server, that was listening for remote connections. I need to unload the module, and reload it with the same parameters as before, just so that ‘Klexel’ can reconnect.

The long-term effect of this will be, that the Linux Tablet may be able to obtain one session on ‘Phosphene’ for sound, but that every time this tablet disconnects, again, that module on Phosphene’s PulseAudio Server will go into a corrupted state.

Hence, I have not yet worked this into a practical solution. But if I ever did, I’d be able to expand the applications of the Linux Guest System – on the Tablet – into audiovisual applications.


 

Update:

I am now one step closer to permitting Linux audiovisual applications on my tablet to access the sound server on my LAN. What I have discovered is, that the module in question can be loaded more than once on the PulseAudio Server, as long as each instance of it listens on a different port number. I.e., the second instance can be configured to listen on port 4318 instead of the default, port 4317. The configuration lines which accomplish this are as follows:

 


load-module module-native-protocol-tcp port=4317 auth-ip-acl=127.0.0.0/8;192.168.2.0/24 auth-anonymous=true auth-cookie-enabled=false

load-module module-native-protocol-tcp port=4318 auth-ip-acl=127.0.0.0/8;192.168.2.0/24 auth-anonymous=true auth-cookie-enabled=false


 

I realize that the legacy Port Number which the PulseAudio Server listens on by default, is 4713. But in Computing, it’s generally impossible for two programs to be listening on the same Port. Therefore this module listens on a different Port Number, just because PulseAudio is already running.

The command ‘pactl list modules‘ confirms that both instances are loaded and stable. Further, when the video-player ‘xine’ is finished with its connection to the server, it closes the TCP Port in a way that does not corrupt the module, so that ‘xine’ can be started a second time and will cause sound to play for the second time.

What this last observation seems to suggest is that the so-called relinquishing of the Local Sound Sink by ‘Klexel’, a Debian 9.11 computer, is corrupted, and not the behaviour of the actual module on the PulseAudio Server, also running on a Debian 9.11 computer.

This is good news. :-)

Screenshot from 2019-09-09 23-45-49

Continue reading Technical Impediment In Getting Sound From My Linux Tablet (Solved)

Print Friendly, PDF & Email

A behaviour of Android that should be understood.

Again, on the subject of The Linux Guest System, installed on my Google Pixel C Tablet

A standard behaviour which Android has, is to serve the request by apps to “Share” documents with other apps, but in a way that non-computing experts may not understand. When the user of an Android app taps on ‘Share’, a list of other apps normally displays, that are registered as being able to open the type of document that’s to be shared. From there, the user can select an app to share it with.

What is usually done behind the scenes is, that the app from which the document is to be shared creates a copy of the document which will be accessible to other apps, and then sends a URI to the app that the document is finally to be shared with. This URI tells the targeted app, which document is to be shared.

In certain cases, these URIs consist of URLs, but in such a way that Android can distinguish between different categories of URLs.

If what is to be shared is a VNC session, again, it’s a URI that specifies the local IP address (127.0.0.1), as well as the port number to connect to.

What I do not know is, when there is only one installed Android app, registered to be able to open a certain category of URI, whether Android nevertheless displays a list of available apps – which in this case would contain only one – so that the user can select the one available app. And this applied to VNC Viewers. What ‘UserLAnd’ was doing, was creating a VNC Session via Linux software, and then allowing a VNC Viewer to connect to that session, but not displaying the fact to me, that it was handing over the Android screen – not the VNC Session – to another app. Two possible things could have been happening:

  1. UserLAnd may just prefer the VNC Viewer that I had installed. It was the recommended viewer. Or,
  2. That VNC Viewer could simply be the only Android app I have installed, that can act as a VNC Viewer, for which reason the dialogue would be redundant, from Android, to ask me which VNC Viewer to use.

Either way, the transfer of the tablet’s screen was seamless, and led me directly into the VNC Session – that is, after I had entered my password for doing so.

Dirk

 

Print Friendly, PDF & Email