Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

hackbunny posted:

Athas posted:

What kind of language support do you envision for fixed point? Just use integers and a printing routine based on the unit you want.

Jesus, what kind of question is this. Full support of course, the same support enjoyed by floating point numbers: printing, parsing, math routines, the whole thing

Athas posted:

Fixed point is indeed nice, but it has serious problems for handling intermediate calculations. For example, computing the distance between two points of magnitude O(n) requires an intermediate result of magnitude O(n*n) if you use the usual Pythagoras formula. This means you might get an overflow in the intermediate result, even if the final result would fit nicely. Floating point is useful in exactly such cases.

Native language support would handle and hide the overflow. It's not like we couldn't multiply 64 bit integers on 32 bit machines, there just wasn't a neat single CPU instruction to do it (there was a neat single built-in function instead)

Next steps: handle rationals like complex numbers by making "rational" a modifier of a base type (rational int16, rational int32 etc.); add first-class arbitrary precision integers; then, put the two together :getin:

Adbot
ADBOT LOVES YOU

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av
Endgame: complex rational bignum :catdrugs:

nielsm
Jun 1, 2009



Athas posted:

code:
fixed res = 0;
for i in n:
  res += (xs[i]-ys[i])**2
res = sqrt(res)
It is not possible (at compile-time) to determine a fixed size for 'res' that will work in all (or even most) cases. You'll (potentially) get problems as soon as n>2. This issue crops up quickly for fairly basic computations, like computing the variance of some samples. You're right that floating point will also break down after a while, but the limit is far harder to reach. There is no replacement for understanding numerics issues, but I'll argue that floating point is more practical when you actually want to do non-trivial computation (but please don't modify my bank account with floating point operations).

Unless you use an arbitrary-magnitude type for 'n', the result size is still bounded. If n is a 32 bit unsigned value, your xs and ys are 16.16 fixed point signed values. The differences would be 16.16 unsigned values (the sign can be discarded since you're squaring them, the compiler would need special casing for this), if you square those you get 32.32 unsigned values.
In a series sum of same-length addends, each addend past the first adds at most 1 carry, so a sum of 2**32 addends adds at most 2**32-1 of carry.
So a 64.32 unsigned value would be sufficient for res. The square root of that should fit in 32.16.

I'd argue that unless you have undecidable side-effects or genuinely unbounded loops, you can always determine an upper bound.
(Regardless, you shouldn't be writing geometry code without understanding the limits of precision and magnitude involved. If you were writing the same thing in floating point, you should probably not even be doing a simple loop sum, but instead a summing tree to avoid problems of precision loss.)

Athas
Aug 6, 2007

fuck that joker

hackbunny posted:

Next steps: handle rationals like complex numbers by making "rational" a modifier of a base type (rational int16, rational int32 etc.); add first-class arbitrary precision integers; then, put the two together :getin:

You can do this in Haskell with the Ratio type, and say 'Ratio Integer' to get a representation based on a pair of arbitrary-precision numbers. It's nice and all, but you open yourself open to arbitrary growth in the Integers involved. It probably wouldn't be particularly hard for an attacker to force you to create increasingly large irreducible fractions. Maybe you could add some sort of threshold, and round once you hit 1KiB or some other magical size limit.

Athas fucked around with this message at 10:38 on Jul 21, 2017

VikingofRock
Aug 24, 2008




Athas posted:

You can do this in Haskell with the Ratio type, and say 'Ratio Integer' to get a representation based on a pair of arbitrary-precision numbers. It's nice and all, but you open yourself open to arbitrary growth in the Integers involved. It probably wouldn't be particularly hard for an attacker to force you to create increasingly large irreducible fractions. Maybe you could add some sort of threshold, and round once you hit 1KiB or some other magical size limit.

There's also CReal, which builds up a whole computation as a series and then calculates it to arbitrary precision only upon displaying the result.

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer

Sagacity posted:

There's a very nice (and extremely weaselly) article about it. It explains why it's actually *good* that this happened.

quote:

blockchain programming is fundamentally different from web development

Ghost of Reagan Past
Oct 7, 2003

rock and roll fun
They're right, don't blame the individual developers involved.

Blame everyone who thought any of this was a good idea.

b0lt
Apr 29, 2005

VikingofRock posted:

There's also CReal, which builds up a whole computation as a series and then calculates it to arbitrary precision only upon displaying the result.

Fun fact: Android's calculator is maintained by Hans Boehm, and is implemented with constructive real numbers.

The Laplace Demon
Jul 23, 2009

"Oh dear! Oh dear! Heisenberg is a douche!"

b0lt posted:

Fun fact: Android's calculator is maintained by Hans Boehm, and is implemented with constructive real numbers.

Extra fun fact:

Hans-J. Boehm posted:

I implemented the arithmetic evaluation engine for the default Android Calculator. It avoids cumulative errors, and provides arbitrarily scrollable, always accurate, results.
Emphasis my own. This is cool.

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Doom Mathematic posted:

How come for(;;) { ... } works, anyway? Shouldn't that at least be for(;true;) { ... }? Or does an empty statement return true??
The direct answer is that it works because the compiler makes it work. And the implicit result is true rather than false because a loop that implicitly terminates rather than implicitly repeating isn't much of a loop.

C's flexible loop statements are something that it gets very, very right, which is why derived languages tend to keep them.

Coffee Mugshot
Jun 26, 2010

by Lowtax
I mean, I know someone asked why, but the answer is that since C99, the second expression in a for statement is evaluated before the loop itself is executed. In this situation, the choice was made to replace an omitted second expression with a non-zero constant. Turns out that in C99, non-zero constants evaluated in a boolean context resolve to true.

C99 standard posted:

The statement for ( clause-1 ; expression-2 ; expression-3 ) behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body... Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero constant.


I wouldn't particularly say that the compiler makes it work (other than generating reasonable code for a "non-zero constant"), it's a part of the C99 language specification.

KernelSlanders
May 27, 2013

Rogue operating systems on occasion spread lies and rumors about me.
Python code:
In [1]: "\q" == "\\q"
Out[1]: True

In [2]: "\a" == "\\a"
Out[2]: False
If I ever invent a language "unrecognized escape sequence" is going to be a compile error.

Linear Zoetrope
Nov 28, 2011

A hero must cook

KernelSlanders posted:

Python code:
In [1]: "\q" == "\\q"
Out[1]: True

In [2]: "\a" == "\\a"
Out[2]: False
If I ever invent a language "unrecognized escape sequence" is going to be a compile error.

It is in Rust:

code:
fn main() {
    println!("\a");
}
code:
   Compiling playground v0.0.1 (file:///playground)
error: unknown character escape: a
 --> src/main.rs:2:16
  |
2 |     println!("\a");
  |                ^

error: aborting due to previous error(s)

error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Doom Mathematic
Sep 2, 2008

Gazpacho posted:

The direct answer is that it works because the compiler makes it work. And the implicit result is true rather than false because a loop that implicitly terminates rather than implicitly repeating isn't much of a loop.

C's flexible loop statements are something that it gets very, very right, which is why derived languages tend to keep them.

So how come while() { ... }, with no condition, is a syntax error?

VikingofRock
Aug 24, 2008




Linear Zoetrope posted:

It is in Rust:

code:
fn main() {
    println!("\a");
}
code:
   Compiling playground v0.0.1 (file:///playground)
error: unknown character escape: a
 --> src/main.rs:2:16
  |
2 |     println!("\a");
  |                ^

error: aborting due to previous error(s)

error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Rust doesn't have a one-character escape sequence for BEL?!

Soricidus
Oct 21, 2010
freedom-hating statist shill

Doom Mathematic posted:

So how come while() { ... }, with no condition, is a syntax error?

for the same reason for () { ... } is a syntax error

sadly the reason is not that you forgot the space before the opening parenthesis, but it ought to have been

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Doom Mathematic posted:

So how come while() { ... }, with no condition, is a syntax error?
Because it's not valid syntax as specified by K&R (predating the standard). My previous answer doesn't imply that it should be otherwise. There are no "empty expressions" in C.

Doom Mathematic
Sep 2, 2008

Gazpacho posted:

There are no "empty expressions" in C.

I don't understand what you mean by this, aren't there at least three empty expressions, possibly four, in for (;;) { }? Does ; by itself evaluate to true?

In any case, it doesn't make sense that omitting the condition in a for loop and omitting the condition in a while loop don't do the same thing. That's strangely inconsistent language design.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Doom Mathematic posted:

I don't understand what you mean by this, aren't there at least three empty expressions, possibly four, in for (;;) { }? Does ; by itself evaluate to true?

In any case, it doesn't make sense that omitting the condition in a for loop and omitting the condition in a while loop don't do the same thing. That's strangely inconsistent language design.

They just decided to add some special cases to the for loop syntax. That's all there is to it. You are thinking about this too much.

Spatial
Nov 15, 2007

Here's another fun C oddity.
code:
int x[10] = { 0 };

int y = 9[x];
int z = x[9];
int w = *(x + 9);
This code compiles and the three variables have the same value.

This still works in C++

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Doom Mathematic posted:

I don't understand what you mean by this, aren't there at least three empty expressions, possibly four, in for (;;) { }? Does ; by itself evaluate to true?

In any case, it doesn't make sense that omitting the condition in a for loop and omitting the condition in a while loop don't do the same thing. That's strangely inconsistent language design.
In K&R and C89 there are three optional expressions. The opening parenthesis can be followed by an expression, or a semicolon. There's no "empty expression" in the latter case. ";" is a delimiter, and has no associated value. In GCC, the parser sets the condition to an empty parse tree here and then the null condition drops the compiler into here to generate a jump back to the top.

In a while loop, the expression just isn't optional. Nobody ever suggested that C was a garden of pure ideology. It gets the job done.

Gazpacho fucked around with this message at 04:51 on Jul 26, 2017

return0
Apr 11, 2007

Spatial posted:

Here's another fun C oddity.
code:
int x[10] = { 0 };

int y = 9[x];
int z = x[9];
int w = *(x + 9);
This code compiles and the three variables have the same value.

This still works in C++

I have Stockholm syndrome because this seems totally normal and expected and cool to me.

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
I think I just saw my first coding horror in the wild (My own code notwithstanding.)

The objective of this function was to distribute a certain number of hours over a month, such that it would fill all available hours on days that still had available hours first, and if it needed to overflow capacity it would distribute the remaining hours evenly across all days (and depending on an option, this could include days that do not allow hours.) Hours have to be divisible by a certain time step (i.e. 15 minutes, 20 minutes, 30 minutes etc.)

The solution? Loop until the hours have all been distributed based on the time step (e.g. if someone wants to distribute 100.000 hours in 30 minute steps it would loop 200.000 times at least to distribute the hours) and for every iteration loop through all days in the month and deposit the hour value of the time step on that day if it has available hours. If a time step was deposited its value is subtracted from the hours to deposit. If the algorithm loops through the entire month without depositing anything, start ignoring available hours and deposit on days that allow hours. The outer loop exits only when all hours have been deposited.

:psyduck:

I asked if I could rewrite it, not so much because it's an O(hours to distribute) algorithm that should be an O(1) algorithm, but more because trying to follow it/fix bugs in it is a pain in the rear end, but got told there was no way to solve the problem in other ways (I also got told the assymptotic running time was really constant, because reasons) and no need for premature optimisations.

Joda fucked around with this message at 22:26 on Jul 25, 2017

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe

Joda posted:

I asked if I could rewrite it, not so much because it's an O(hours to distribute) algorithm that should be an O(1) algorithm, but more because trying to follow it/fix bugs in it is a pain in the rear end, but got told there was no way to solve the problem in other ways (I also got told the assymptotic running time was really constant, because reasons) and no need for premature optimisations.

All algorithms have O(heat death of the universe) as an upper bound on their runtime, which as far as we know is a constant, which means all algorithms are O(1).

Also, I'd love to see your O(1) solution to this problem. Sure you got your notation right there? :v:

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe

TooMuchAbstraction posted:

Also, I'd love to see your O(1) solution to this problem. Sure you got your notation right there? :v:

I'm probably wrong, but I think so? There's a constant number of days in a month, and I'm like 99% sure there's a solution whose running time will not depend on the number of hours to distribute. Too tired to wrack my brain with it right now, but I'm interested enough to give it a shot later.

return0
Apr 11, 2007
I think there is a closed form solution, but I'm not thinking much.

Rubellavator
Aug 16, 2007

Joda posted:

I'm probably wrong, but I think so? There's a constant number of days in a month, and I'm like 99% sure there's a solution whose running time will not depend on the number of hours to distribute. Too tired to wrack my brain with it right now, but I'm interested enough to give it a shot later.

Does your fancy O(1) solution take into account leap years?! how about months that don't have the same number of days of which there are many.

ChaosArgate
Oct 10, 2012

Why does everyone think I'm going to get in trouble?

ASP drove me up the wall at work earlier. I've never formally learned, so I basically dived into the deep end with it, but I was having a real hard time trying to get a SQL Server RecordSet as some kind of array I could gently caress around with in ASP. I got it eventually, but because there's no real good way to print an object in ASP for debugging, I wrote it to a JSON that was being written out to another file that I actually could read and it looked like a plain old array. As it turns out, it was actually a two-dimensional array that got flattened out when written to a JSON for some reason, which makes sense in hindsight, but it's still kind of annoying to deal with. As you'd expect, accessing any object in that array requires two coordinates, column number and row number. I have no idea why, but this array was ordered by column first, which means that getting the length of this array meant I was getting the column count, which kind of sucks because the column count is static and I wanted to iterate over an indeterminate number of rows! UBound at least has an optional parameter that lets you identify which dimension of the array you want to get a count of, which is helpful, at least.

Another thing that just baffled me about ASP earlier is how it handled this for loop (written in Python for convenience):
code:
str = "Example"
for i in list(range(5)):
    str = "REPLACE("+str+", a, b)"
The idea was to make a nested REPLACE call for a SQL query, but ASP couldn't handle that for some reason and just fuckin died whenever I tried that as a for loop. I ended up making a recursive function for that instead, which did the job nicely, but wow, that's 30 min I'm not getting back.

baquerd
Jul 2, 2007

by FactsAreUseless

Joda posted:

I asked if I could rewrite it, not so much because it's an O(hours to distribute) algorithm that should be an O(1) algorithm, but more because trying to follow it/fix bugs in it is a pain in the rear end, but got told there was no way to solve the problem in other ways (I also got told the assymptotic running time was really constant, because reasons) and no need for premature optimisations.

Sounds like a premature optimization. What's the business problem that speeding this up will solve?

megalodong
Mar 11, 2008

code:
$(document).ready(function () {
	...
	3357 lines later
});

idiotmeat
Apr 3, 2010

Joda posted:

I'm probably wrong, but I think so? There's a constant number of days in a month, and I'm like 99% sure there's a solution whose running time will not depend on the number of hours to distribute. Too tired to wrack my brain with it right now, but I'm interested enough to give it a shot later.
Yeah, you're right. The solution depends on the number of days with available slots. Since the linux scheduler once claimed O(1) for its loop through 40 priorities I think the same can be said here for a loop up to 31 days (sorry smarch).

Foxfire_
Nov 8, 2010

Spatial posted:

Here's another fun C oddity.
code:
int x[10] = { 0 };

int y = 9[x];
int z = x[9];
int w = *(x + 9);
This code compiles and the three variables have the same value.

This still works in C++

z and w are things working totally normally. y is undefined behavior that will probably work on modern architectures.

Thou shalt not form any pointers that ever point to anything besides 0 or between the start of an array and one past its end, even if you never dereference them.

It'd crash on some old CPUs with dedicated base and offset registers (like things with a 16 bit memory space and 8 bit registers where pointers are done with register pairs).

vOv
Feb 8, 2014

Foxfire_ posted:

z and w are things working totally normally. y is undefined behavior that will probably work on modern architectures.

Thou shalt not form any pointers that ever point to anything besides 0 or between the start of an array and one past its end, even if you never dereference them.

It'd crash on some old CPUs with dedicated base and offset registers (like things with a 16 bit memory space and 8 bit registers where pointers are done with register pairs).

y is always legal because a[x] is defined as *(a + x).

ullerrm
Dec 31, 2012

Oh, the network slogan is true -- "watch FOX and be damned for all eternity!"

Foxfire_ posted:

z and w are things working totally normally. y is undefined behavior that will probably work on modern architectures.

Incorrect. C99 language spec:

quote:

6.5.2 Postfix operators

code:
postfix-expression := ... | postfix-expression [ expression ]

6.5.2.1 Array subscripting

Constraints

1 One of the expressions shall have type ‘‘pointer to object type’’, the other expression shall have integer type, and the result has type ‘‘type’’.

Semantics

2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that
code:
E1[E2]
is identical to
code:
(*((E1)+(E2)))
.

Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

The expression 7[x] is not only valid, it's guaranteed to have the same result as x[7], because the conversion rules for binary + are transitive.

Note that, IIRC, this changed in C++11 and later.nvm

Foxfire_ posted:

Thou shalt not form any pointers that ever point to anything besides 0 or between the start of an array and one past its end, even if you never dereference them.

Wat. I don't know how you ever came to that conclusion. A pointer is just an address number; if you don't dereference it, it does nothing. C and C++ are not garbage-collected languages, a pointer pointing to something it doesn't own / cannot own is harmless as long as you do nothing with it.

Foxfire_ posted:

It'd crash on some old CPUs with dedicated base and offset registers (like things with a 16 bit memory space and 8 bit registers where pointers are done with register pairs).

Are you thinking about the old 8088 and its segment selector registers? It wouldn't quite crash, no, although it might not do what you were planning. Working with segment registers is basically identical to working with paged RAM, just much simpler and easier. The worst part of it was just having to deal with separate types for near/far pointers.

ullerrm fucked around with this message at 06:26 on Jul 26, 2017

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
It's defined in C89 and C++, undefined in C99 (type constraints).

It's also pretty benign.

VikingofRock
Aug 24, 2008




ullerrm posted:

Note that, IIRC, this changed in C++11 and later.

Do you have any details on this? I can't find anything about this change online.

JewKiller 3000
Nov 28, 2006

by Lowtax
if you would ever write something like 7[x] you are such an irredeemable idiot that no standard can possibly help you

ullerrm
Dec 31, 2012

Oh, the network slogan is true -- "watch FOX and be damned for all eternity!"

VikingofRock posted:

Do you have any details on this? I can't find anything about this change online.

I stand corrected, it still allows either ordering as of C++14.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

ullerrm posted:

Wat. I don't know how you ever came to that conclusion. A pointer is just an address number; if you don't dereference it, it does nothing. C and C++ are not garbage-collected languages, a pointer pointing to something it doesn't own / cannot own is harmless as long as you do nothing with it.

Doing pointer arithmetic that creates a bad pointer puts you straight into undefined behavior territory (though it's one of those undefined behaviours which is often tolerated by compilers). See 5.7.4 in the standard.

For example, merely computing the value can cause an overflow trap if it's outside the allowed range (while if the newly-computed pointer is inside the allowed range, the compiler must ensure that it doesn't overflow).

Adbot
ADBOT LOVES YOU

Dylan16807
May 12, 2010

ullerrm posted:

Wat. I don't know how you ever came to that conclusion. A pointer is just an address number; if you don't dereference it, it does nothing. C and C++ are not garbage-collected languages, a pointer pointing to something it doesn't own / cannot own is harmless as long as you do nothing with it.

Wrong on that count. 7[x] is fine because the 7 isn't a pointer. If you make a pointer to address 7, it's undefined behavior whether you use it or not.


Jabor posted:

Doing pointer arithmetic that creates a bad pointer puts you straight into undefined behavior territory (though it's one of those undefined behaviours which is often tolerated by compilers). See 5.7.4 in the standard.

For example, merely computing the value can cause an overflow trap if it's outside the allowed range (while if the newly-computed pointer is inside the allowed range, the compiler must ensure that it doesn't overflow).

Often tolerated, with the notable exception of making certain null checks invalid if you create a pointer to a field before checking against null.

Edit: at least I think that variant of the problem existed. I know 'harmless' dereferences can render null checks invalid.

Dylan16807 fucked around with this message at 08:12 on Jul 26, 2017

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply