Author Topic: The _HYPOT command  (Read 7622 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: The _HYPOT command
« Reply #15 on: September 23, 2018, 01:53:16 am »
I'm still ending up faster with _HYPOT than the plain math formula, but that may be because I've tweaked the compiler switches in the past for math speed (-ffast-math, I think, and maybe -o4 as well).

One important note with _HYPOT: It prevents rounding and overflow errors from occurring in the intermediate steps to getting your answer.

For example:   X * X + Y * Y > the DOUBLE limit...  Your answer would be wrong as it'd overflow down, before the SQR ever occurs.

Not that most people would ever run into this issue, but if your math is large enough, it could be an issue, and _HYPOT is supposed to not have that issue.


Edit:  Wiki actually has a good explaination of it here:  https://en.m.wikipedia.org/wiki/Hypot
« Last Edit: September 23, 2018, 02:01:06 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: The _HYPOT command
« Reply #16 on: September 23, 2018, 03:15:51 am »
Here are the results for my most-average-in-the-world laptop (Win10 64 bit) with last month's QB64 build and no math tweaks:

The _HYPOT command is several factors slower when I test it.

And I'm trying to parse
Quote
Not that most people would ever run into this issue, but if your math is large enough, it could be an issue, and _HYPOT is supposed to not have that issue.

... so does the author believe this is a general and powerful command, or no? Is the DOUBLE limit part of its construction as opposed to float, long, integer, or some other type limit? (Maybe I didn't read carefully which is possible. Are you saying _HYPOT handles all the types without bias? My bad, it's been a minute!)
« Last Edit: September 23, 2018, 03:34:04 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: The _HYPOT command
« Reply #17 on: September 23, 2018, 03:43:52 am »
Quote
Why is the DOUBLE limit part of its construction as opposed to float, long, integer, or some other type limit? (Maybe I didnt read carefully which is possible.)

Double, I believe, because that's what gcc uses internally for these type of calculations.

Add a 8-byte value to a 8-byte value, and try and store it in a 8-byte return value...  If the 2 numbers are too large, you get overflow.

Think of it like changing (a + b) / 2 into a + (b - a) / 2...   In cases where a + b are too large for the internal return variable to hold, the math overflows and is wrong.  a + (b - a) / 2 isn't going to have that issue.

*******************

In the end, it seems as if SQR(a * a + b * b) is ending up faster for most people, (which honestly shocks me from my personal results in the past), but _HYPOT is still the routine to use for extreme large/small/precision cases. 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: The _HYPOT command
« Reply #18 on: September 23, 2018, 03:45:07 am »
Looking at the Wiki link provided I can see why _HYPOT would be slower now because of the substitution needed to prevent overflow.

double hypot(double x,double y)
    x = abs(x);
    y = abs(y);
    if (y > x) swap(x, y);
    if (x == 0.0) return y;
    double t = y / x;
    return x * sqrt(1 + t * t);
In order to understand recursion, one must first understand recursion.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: The _HYPOT command
« Reply #19 on: September 23, 2018, 03:48:52 am »
Aye, thanks fellas. Makes a bit more sense now. Scared me for a second!

(I have a fantasy of computers having only one number type one day... I hate having to know things about programming that never explicitly arose from mathematics but are only still around due to tradition...)
You're not done when it works, you're done when it's right.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: The _HYPOT command
« Reply #20 on: September 23, 2018, 03:58:34 am »
Looking at the Wiki link provided I can see why _HYPOT would be slower now because of the substitution needed to prevent overflow.

double hypot(double x,double y)
    x = abs(x);
    y = abs(y);
    if (y > x) swap(x, y);
    if (x == 0.0) return y;
    double t = y / x;
    return x * sqrt(1 + t * t);

I think what the gcc compiler does is a little more:

IF x < y then
  if x = 0 return y
  return x * sqrt(1 + y / x * y / x)
Else
  if y = 0 return x
  return y * sqrt(1 + x / y * x/ y)
End If

Which saves a few function calls, but is still more complicated than the direct math would be.
« Last Edit: September 23, 2018, 04:00:30 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: The _HYPOT command
« Reply #21 on: September 23, 2018, 09:04:09 am »
Aha! There is a work around for neg numbers?

I was working circle fill routines with same formula as Terry had shown and got hung by negative value coming up somewhere in calculation both SQR and ^.5, crash.

Wait how can you get a neg when A * A + B * B would cancel it? Don't know but I had a circle fill routine that refused to work unless I loose time to check for negs or loose time calling ABS.

Hmm... now I wonder if, .... no I was still not using Octants back then.

But I see now the formula does use ABS calls, well the one from Wiki, if Steve is corrrect:
Quote
I think what the gcc compiler does is a little more:

IF x < y then
  if x = 0 return y
  return x * sqrt(1 + y / x * y / x)
Else
  if y = 0 return x
  return y * sqrt(1 + x / y * x/ y)
End If

Which saves a few function calls, but is still more complicated than the direct math would be.

Then gcc compiler might not be doing enough, I think the ABS calls are needed.

Come to think, I might have been getting negative numbers because the type I was using was too small?
350 * 350 > integer range but I don't think I was working in integers... I digress.
« Last Edit: September 23, 2018, 09:23:33 am by bplus »

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: The _HYPOT command
« Reply #22 on: September 23, 2018, 09:50:22 am »
man all you guys got better machines than mine. between the two types the numbers are nearly identical for me.
3.35 _HYPOT
3.68 _OTHER (0.715 changing ^2 to *a,*b)
Granted after becoming radioactive I only have a half-life!

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: The _HYPOT command
« Reply #23 on: September 23, 2018, 09:56:37 am »
Squaring by exponentiation is slower than the straight a * a procedure. In any case for this function, I'd use that construction. as an inlined function, calculation is approximately 20% faster than _HYPOT. (7.849s versus 9.98s for _hypot) at n=10000. For convenience, perhaps. As a matter of algorithmic choice for _HYPOT, no.
« Last Edit: September 23, 2018, 01:03:49 pm by codeguy »

Offline luke

  • Administrator
  • Seasoned Forum Regular
  • Posts: 324
    • View Profile
Re: The _HYPOT command
« Reply #24 on: September 25, 2018, 10:09:02 am »
In x64 Linux I get the _HYPOT version about twice as fast. If I change everything to use INTEGERs the math stuff version is about the same, whereas _HYPOT is now about 7 times faster (Terry: make sure you leave the timer variables as floats otherwise they'll be rounded to integers).

_HYPOT is implemented as a direct call to the C hypot() function. The manual states "The calculation is performed without undue overflow or underflow during the intermediate steps of the calculation", which supports what Steve was saying about intermediate overflow.

I traced the execution of _HYPOT and on my machine, at least, it's using SSE instructions to do the calculation. I'd be curious to know if perhaps 32 bit machines are doing more work because of their reduced register width to shunt the data around.
« Last Edit: September 25, 2018, 10:15:32 am by luke »

Offline PMACKAY

  • Forum Regular
  • Posts: 188
  • LIFE is Temporary
    • View Profile
Re: The _HYPOT command
« Reply #25 on: September 25, 2018, 10:21:43 am »
Linux Mint 19. just copied straight and run..

64bit 1.2qb64x64

« Last Edit: September 25, 2018, 10:24:53 am by PMACKAY »
MackyWhite