January 22, 2003
"Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> writes:
> Given ints a and b, one can swap them without using a temporary variable:
>
> b = a + b;
> a = b - a;
> b = b - a;

Or, if you want to avoid the tedious and error-prone arithmetic operations, you can use the classic alternative:

    a ^= b;
    b ^= a;
    a ^= b;

Enough with jokes... To be serious, I thought about the tuples a while and decided that probably it would be the best to implement tuple assignments as a following translation:

// assume Type1 t1, Type2 t2, ..., TypeN tN;

t1, t2, ..., tN = expr1, expr2, ..., exprN;

would be translated to

Type1 tmp1; Type2 tmp2; ...; TypeN tmpN;
tmp1 = expr1; ...; tmpN = exprN;
t1   = tmp1;  ...; tN   = exprN;

So that even "a, b = b, a" would work intuitively and unnecessary temporaries would be removed by the compiler.

Tuples don't come free.

With the above-mentioned syntax they might cause slight parsing problems. Most visibly, they might would make the comma operator unusable because it would be indistinguishable from the tuples. So the alternatives seem to be "keep the comma operator and use a different syntax for tuples", "introduce special cases where comma operator can be used in tuples (for example inside parens)", and "change the comma operator to a different form or otherwise render it unusable".

Antti
January 22, 2003
"Ilya Minkov" <midiclub@8ung.at> wrote in message news:b0n2c8$1m2s$1@digitaldaemon.com...
> Mike Wynn wrote:
> > the usual form is
> > a = a ^ b;
> > b = a ^ b;
> > a = a ^ b;
>
> This math is not better, IMO. Same 3 operations, all of them atomic (1 m-op), and execute in any pipe. So on intel, and all the others shouldn't be very different.

this maths is a lot better, 1, it's bitwise so carry flag does not effect
the op and the op does not effect the carry.
and 2 its the same op rather 3 times, due to the self inverse behaviour of
xor.

>
> And when doing such things, originality matters more, since the *usual* way would be to swap registers with a dedicated command!
>
by *usual* I mean the usual swap 2 reg only usung 2 reg's is done with xor, not I usually swap that way

I totally agree (please read my comments)

BUT most CPU's that have swap/exchange ONLY have reg, [reg]
not reg, reg
and in the old days there where no exchange op's and less registers, no
pipelines, only one alu etc etc etc.

mov r2, r1; mov r1, r0; mov r0, r2;  <- 3 op's uses 3 regs
xor r1, r1, r0; xor r0, r1, r0; xor r1, r1, r0 <- 3 ops uses 2 regs

that's the only reason, apart from being a mathmatical curiosity

xchg on the x86 asserts the lock, which stall things so it is avoided unless needed

and how often do you need to swap 2 values ?
I've got more code that uses rotates `a = ((b<<c)|(b>>-c));` than used swaps




January 22, 2003
"Antti Sykari" <jsykari@gamma.hut.fi> escreveu na mensagem news:86u1g0dfyu.fsf@hoastest1-8c.hoasnet.inet.fi...
> "Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> writes:
> > Given ints a and b, one can swap them without using a temporary
variable:
> >
> > b = a + b;
> > a = b - a;
> > b = b - a;
>
> Or, if you want to avoid the tedious and error-prone arithmetic operations, you can use the classic alternative:
>
>     a ^= b;
>     b ^= a;
>     a ^= b;
>
> Enough with jokes... To be serious, I thought about the tuples a while and decided that probably it would be the best to implement tuple assignments as a following translation:
>
> // assume Type1 t1, Type2 t2, ..., TypeN tN;
>
> t1, t2, ..., tN = expr1, expr2, ..., exprN;
>
> would be translated to
>
> Type1 tmp1; Type2 tmp2; ...; TypeN tmpN;
> tmp1 = expr1; ...; tmpN = exprN;
> t1   = tmp1;  ...; tN   = exprN;
>
> So that even "a, b = b, a" would work intuitively and unnecessary temporaries would be removed by the compiler.
>
> Tuples don't come free.
>
> With the above-mentioned syntax they might cause slight parsing problems. Most visibly, they might would make the comma operator unusable because it would be indistinguishable from the tuples. So the alternatives seem to be "keep the comma operator and use a different syntax for tuples", "introduce special cases where comma operator can be used in tuples (for example inside parens)", and "change the comma operator to a different form or otherwise render it unusable".
>
> Antti

Hi,

    This work for this particular case of tuple construction/deconstruction,
but usually people will use that with functions, like:


ComparableCollection numbers = ...;
int min, max = numbers.bounds();


    So generic tuples must work like structs, accessing defined stack areas
(nothing forbids the compiler to generate code like what you did for this
special case). Of course all this talk about tuples would make in/out/inout
kind of obsolete. About tuple syntax, we can force people using parenthesis
in tuples, so it should look like:


(a,b) = (b,a);

    And defined method call based on tuple passing, so calling "foo(a,b,c);"
is giving foo the tuple (a,b,c). Empty tuples would come free, and single
element tuples too. With this in mind we could say that every single value
is equivalent to a single element tuple, so we can still use parenthesis to
reorder expressions, but it'll just create single element tuples. That could
render the comma operator useless. It's semantics could be emulated by a
simple (but strange) rule for tuples: tuples are pruned from left to right
to fit in their targets:


int a = (1,2,3,4); // a is 4
int (a,b) = (1,2,3,4); // a is 3, b is 4
int (a,b,c) = (1,2,3,4); // a is 2, b is 3, c is 4
int (a,b,c,d) = (1,2,3,4); // a is 1, b is 2, c is 3, d is 4


    But I think this is most likely to cause bugs. There is any idiom that
the comma operator (as is stands today) makes clearer?
    As a side note if we unify this tuple construction/deconstruction rules
with function call we can end with functional languages syntax, so:


omparableCollection numbers = ...;
Range bounds = new Range numbers.bounds(); // function application


or we can force the parenthesis:


Range bounds = new Range(numbers.bounds());


    Which can also lead to unmaintainable code. Also with single value =
single element tuple paradigm, we'll flatten more tuples than usual:


((((1))),((2,3),((4))),(5)) // I feel lispish today ;-)


will become:


(1,((2,3),4),5)


    Which may be a good thing. Or not ;-)

    Best regards,
    Daniel Yokomiso.

"The consumer is not an idiot, she is your wife."
- David Ogilvy, founder of Ogilvy & Mather


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.443 / Virus Database: 248 - Release Date: 10/1/2003


January 23, 2003
On Wed, 22 Jan 2003 20:43:02 -0000, Mike Wynn <mike.wynn@l8night.co.uk> wrote:
> it's use is to swap to cpu registers without a 3rd or a store+load
> but otherwise its pointless most cpus have a swap op these days
> x86 has reg, mem exchange anyway (though it does lock)
> Arm has reg, [reg] exchange

Which you would never want to use unless you need atomicity (or perhaps if optimizing for space is your primary concern); otherwise, it's faster to do it manually.  Plus, on some ARMs, SWP bypasses the cache.

In fact, on non-super-scalar chips such as most if not all ARMs, the math tricks might actually be the best way to do the exchange, since you never have to spill a register for a temporary, and the chained result dependencies aren't an issue.  It's three instructions either way...

> I'm sure PPC and MIPS have similar.

They don't; they use a load locked/store conditional mechanism to achieve atomicity.  They also have enough registers that using a third is unlikely to be a problem. :-)

-Scott
January 23, 2003
What I'm saying is that Joe Programmer should not have to implement this *crap*, for any type, let alone all types.  Swap is a basic intrinsic operation and should be defined by the language for everything that's assignable.  Then the compiler can generate whatever wierd code is needed to perform the swap optimally for the platform.   Think semantics, not implementation.

Same goes for min, and max.  If you have to have the compiler "figure out what you meant" after the fact, it can't be depended upon.  Better to just tell it exactly what you intend.

Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code I've
seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the
works.  That might be a counterargument, in fact.  ;)  But you should be
able to trust the compiler to generate good code if you call abs() or
fabs();  I wouldn't expect a compiler to turn (f < 0 ? -f : f) into
something that has no branches.  But if it does, great.  I'm just not gonna
depend on it.

There should be a certain baseline for functionality;  all machines either support swap, min, max, abs natively, or have the mechanisms to implement them.  That's fundamental computing.

Look at the mess Windows made with MIN and MAX #defines (actually it also #define's min and max as well, confounding ISO std::C++)

It would pay to do a thorough job of covering the fundamentals, up front.

Rotate is also a good candidate.  It's in C library for most platforms anyway even if it's not standard.  As someone pointed out, it can be implemented easily with two shifts and an or, *if* the cpu happens to lack such an operation.  I think that would be rare.  Anyone that can implement a compiler can do code generation for rotate, no problem.  It wouldn't burden implementors one bit.  It would be a useful addition to the D language.

Any other common low level stuff that isn't in D?

clamp (just a wrapper around a min and max combo).
test if in range.
Inexact comparison for floats (f1 ?= f2  generates  abs(f1 - f2) < epsilon,
though specifying what epsilon should be would be an issue).
div+mod combination
converting from float to int with various forms of rounding, at bare minimum
truncate and round nearest, which are implementable in terms of each other.
power function  x**y  or  pow(x,y)

I'm running out of them.  There aren't that many.

The upside to this is that if new operators are added for these, that's just that many more operators we can overload later.  ;)

Sean

"Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> wrote in message news:b0mvt1$1kjh$1@digitaldaemon.com...
> It's not intended to be sane, fast or easy to understand, but it doesn't
use
> ANY temporary variables. It's just to prove that it can be written without extra storage. I'm not saying that D should do this, or that this is good programming.


January 23, 2003
"Sean L. Palmer" <seanpalmer@directvinternet.com> escribió en el mensaje
news:b0o345$27ls$1@digitaldaemon.com...
| Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code
I've
| seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the

Actually, that brings me to this question: if I import, let's say, c.stdio
and I only use printf(), does dmd still compile the other functions? I know
that if I don't use anything from the module, dmd ignores it, but what about
specific things?
The reasoning behind doing what you said is the same: why would I import
(include, in this case) sqrt, sin, cos, etc., when I only need abs?

—————————————————————————
Carlos Santander
http://carlos3.netfirms.com/
"Sean L. Palmer" <seanpalmer@directvinternet.com> escribió en el mensaje
news:b0o345$27ls$1@digitaldaemon.com...
| Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code
I've
| seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the

Actually, that brings me to this question: if I import, let's say, c.stdio
and I only use printf(), does dmd still compile the other functions? I know
that if I don't use anything from the module, dmd ignores it, but what about
specific things?
The reasoning behind doing what you said is the same: why would I import
(include, in this case) sqrt, sin, cos, etc., when I only need abs?

—————————————————————————
Carlos Santander
http://carlos3.netfirms.com/


January 23, 2003
Carlos Santander B. wrote:
> "Sean L. Palmer" <seanpalmer@directvinternet.com> escribió en el mensaje
> news:b0o345$27ls$1@digitaldaemon.com...
> | Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code
> I've
> | seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the
> 
> Actually, that brings me to this question: if I import, let's say, c.stdio
> and I only use printf(), does dmd still compile the other functions? I know
> that if I don't use anything from the module, dmd ignores it, but what about
> specific things?
> The reasoning behind doing what you said is the same: why would I import
> (include, in this case) sqrt, sin, cos, etc., when I only need abs?

Importing a library does not cause the functions of that library to be included in your binary - unless, of course, the compiler chooses to inline the function.

Instead, each function exists in the .o (or library file) that corresponds with where the function was defined.

January 24, 2003
> On Tue, 14 Jan 2003 12:19:44 +0000, boda wrote:
> > I just heard about D, and I read that new features can still be added, so I thought I'd suggest an 'interchange' operator (for example, ><), that exhanges the two operands, such that a><b is equivalent to aux=a; a=b; b=aux. It seemed useful to me on many ocasions, it is very easy to implement, and it makes code simpler to write and read. It is also quicker (it elimnates the need for aux and, for references, it can be implemented with two xor's). So, why isn't there one yet?

  I might point out that in mathematics my experience is that
mathematicians generally use max( 1,2..n ) style of notation and do not
generally use a symbol. (although I have seen the traditional union
symbol used as max in a web page on trinary arithmetic)

  I would argue that using mathematical symbols in languages is a
positive thing, commonly accepted mathematical symbols are 'useful'
(especially for numerical computing), and also tend to map well into
code construction. So thus every language almost universally uses
mathematical equality symbols (=,>,<, etc), and basic arithmetic symbols
(+,-,*, etc).
  But for symbols that are not in ascii there is less agreement on how
to represent them in a programming language. Most languages just use
ascii symbols, or just use the names of the operation written out (ie.
AND and OR).
  I say that we should reinstate the 'proper' mathematical symbols.
  Add U+00f7 for /, add U+2264 and U+2265 for <= and >=, etc.
  Cons: some mathematical symbols do not distinguish between binary and
logical operations, ie U+2227 could be used for bitwise or logical AND.
  Oh and it's also a pain in the arse to type, well for most ppl who use
latin keyboards.

  And bring in all the set notation too, with all the generics going on
nowadays, those would be quite useful.

  Or at the very least, allow unicode to be in identifiers and allow the
user to define binary operators, with the operator defined by a user
keyword. Hmm dunno what the syntax would be for something like that, the
standard way of writing binary operations only allows for overloading
operators. hmm maybe something like:
  T operator xor( T, T )
  Ohh, I've gone all C++..

  - Factory




February 07, 2003
"Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> wrote in message news:b0mq5b$1h7f$1@digitaldaemon.com...
> Given ints a and b, one can swap them without using a temporary variable:
>
> b = a + b;
> a = b - a;
> b = b - a;

If one did this as a generic operation on types, it would screw up the garbage collector. This is because if the thread was halted in the middle of such a calculation to check for pointers, one of the pointers would be scrambled, and would be missed.

A generic implementation would have to use temporaries.


1 2
Next ›   Last »