# dec*(), *dec(), base_convert() and negative numbers

- Thread: https://externals.io/message/24981
- Original archive: https://news-web.php.net/php.internals/24981
- Started by Matt W on 2006-07-26T09:26:53+00:00
- Messages: 8
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #24981 — Matt W — 2006-07-26T09:26:53+00:00

URL: https://externals.io/message/24981#24981

Hi all,

I was just updating the dec[bin|hex|oct] functions to convert numbers >=
2^32 since the [bin|hex|oct]dec counterparts were updated way back in PHP
4.1.

My question is if negative numbers should be handled any differently.  Now
negative longs are converted to unsigned which gives a weird result for
regular users IMO.  The *dec() functions ignore negative strings.  Because
of the way `base_convert()` works, if you pass a negative number (gets
converted to string), the result will be from the absolute value instead of
what you get with dec*().

*) Should the dec*() functions continue to convert negative longs to
unsigned and use absolute value for doubles?

*) Should absolute value always be used, like with `base_convert()`?

*) Should everything be changed to support negative numbers going both
directions (to or from base)?


Thanks,
Matt

---

## #24997 — Matt W — 2006-07-27T10:40:52+00:00

URL: https://externals.io/message/24981#24997 · In reply to: #24981

Hi again,

I realize I might not get any answer about updating these little ol'
functions :-/, but it'd be nice to hear something one way or the other so I
can submit an acceptable patch with correct behavior.

After thinking about it more, are negative numbers even "officially
supported" with the dec[bin|hex|oct] functions?  You won't get anything
close to the original back with *dec(dec*(-123)).

Since `base_convert()` uses the number's absolute value, I'm thinking the only
reason for using "unsigned long" for the dec*() functions is to handle cases
where a PHP double is between LONG_MAX and ULONG_MAX.  If so, I think
absolute value can be used everywhere.

Or again, should I update the functions to correctly accept and return
negative values?  But I'm not sure if negative bin/hex/oct strings are
desired (semantically).

Thanks for any simple guidance!


Matt


----- Original Message -----
From: "Matt W"
Sent: Wednesday, July 26, 2006


> Hi all,
>
> I was just updating the dec[bin|hex|oct] functions to convert numbers >=
> 2^32 since the [bin|hex|oct]dec counterparts were updated way back in PHP
> 4.1.
>
> My question is if negative numbers should be handled any differently.  Now
> negative longs are converted to unsigned which gives a weird result for
> regular users IMO.  The *dec() functions ignore negative strings.  Because
> of the way `base_convert()` works, if you pass a negative number (gets
> converted to string), the result will be from the absolute value instead
of
> what you get with dec*().
>
> *) Should the dec*() functions continue to convert negative longs to
> unsigned and use absolute value for doubles?
>
> *) Should absolute value always be used, like with `base_convert()`?
>
> *) Should everything be changed to support negative numbers going both
> directions (to or from base)?
>
>
> Thanks,
> Matt

---

## #24999 — Michael Wallner — 2006-07-27T12:28:52+00:00

URL: https://externals.io/message/24981#24999 · In reply to: #24997

Matt W wrote:
> Hi again,
> 
[...]

I don't see what you're trying to fix.

$ cli -r 'var_dump((int)hexdec(dechex(-123)), (int)(float)sprintf("%u",-123), (int)0xffffff85);'
int(-123)
int(-123)
int(-123)

Regards,
-- 
Michael

---

## #25006 — Matt W — 2006-07-27T13:10:18+00:00

URL: https://externals.io/message/24981#25006 · In reply to: #24999

Hi Michael,

----- Original Message -----
From: "Michael Wallner"


> Matt W wrote:
> > […]
> [...]
>
> I don't see what you're trying to fix.
>
> $ cli -r 'var_dump((int)hexdec(dechex(-123)),
(int)(float)sprintf("%u",-123), (int)0xffffff85);'
> int(-123)
> int(-123)
> int(-123)

The main "fix" (upgrade) is to let the dec*() functions convert numbers >=
2^32.  But I'm *wondering* whether *this* should be changed:

C:\math-old>php -r "var_dump(hexdec(dechex(-123)));"
float(4294967173)

Your (int) typecast changed that of course.

If the dec*() functions handle numbers whose absolute value is >= 2^32, how
is a negative double supposed to be handled?  Absolute value, I assume.  But
that's different than negative int handling now (internal long converted to
unsigned long).  If double's were to be the same way, and there was an
unsigned double type, passing -5000000000 would result in an insanely huge
number after being made "unsigned" internally like now.

That's why I'm assuming negative numbers aren't "really" supported now (not
in any form with `base_convert()`), but it's simply a side effect of wanting
to handle *positive* numbers between LONG_MAX and ULONG_MAX.  e.g. when
doing dechex(4294967173) that's a PHP double, but it gets converted to long
(becomes -123), and finally unsigned long (recovering 4294967173).  IOW,
after convert_to_long() in dec*() it doesn't know if -123 or 4294967173 was
passed.  Make sense?  (Actually, it doesn't, that's my point. :-))

So after more thinking, I figure when upgrading dec*() to handle any number,
absolute value should be used (then int(123) would be returned in my
example).  Unless the all the functions are changed to properly
accept/return negatives... I personally don't care either way on that.

> Regards,
> -- 
> Michael

Matt

---

## #25008 — Michael Wallner — 2006-07-27T13:43:27+00:00

URL: https://externals.io/message/24981#25008 · In reply to: #25006

Matt W wrote:

> That's why I'm assuming negative numbers aren't "really" supported
> now (not in any form with `base_convert()`), but it's simply a side
> effect of wanting to handle *positive* numbers between LONG_MAX and
> ULONG_MAX.  e.g. when doing dechex(4294967173) that's a PHP double,
> but it gets converted to long (becomes -123), and finally unsigned
> long (recovering 4294967173).  IOW, after convert_to_long() in dec*()
> it doesn't know if -123 or 4294967173 was passed.  Make sense?
> (Actually, it doesn't, that's my point. :-))

For your computer 0xffffff85 is -123 and 4294967173.  It's just how
you look on it.

> So after more thinking, I figure when upgrading dec*() to handle any
> number, absolute value should be used (then int(123) would be
> returned in my example).  Unless the all the functions are changed to
> properly accept/return negatives... I personally don't care either
> way on that.

No way. Why should hexdec(dechex(-123)) return +123?

-- 
Michael

---

## #25012 — Matt W — 2006-07-27T14:06:50+00:00

URL: https://externals.io/message/24981#25012 · In reply to: #25008

Hi Michael,

----- Original Message -----
From: "Michael Wallner"
Sent: Thursday, July 27, 2006


> Matt W wrote:
>
> > […]
>
> For your computer 0xffffff85 is -123 and 4294967173.  It's just how
> you look on it.

Oh, I know.  But that still doesn't answer the question of how to handle
negative *double's*.

> > […]
>
> No way. Why should hexdec(dechex(-123)) return +123?

Because it makes more sense to users than 4294967173? :-)  They don't care
what's stored as 0xffffff85, blah blah, just what they actually see.  Oh,
and doing the same to/from using -123 and `base_convert()`, you'll get +123!

IMO, it was *wrong* to convert a negative to unsigned long.  Absolute value
should've been used like with base_convert (though that may be by chance
rather than design :-)).  Of course, it could all be very
consistent/logical, to me, by accepting/returning negatives.  But what are
the thoughts on negative base 2-36 strings?  No-no's?

> -- 
> Michael

I appreciate your replies.  I'll be gone for a while now, so I won't be
bothering you with another e-mail. :-P


Matt

---

## #25032 — Matt W — 2006-07-28T08:21:02+00:00

URL: https://externals.io/message/24981#25032 · In reply to: #25008

Hi,

More thoughts...

I forgot to say last time that the manual doesn't mention the dec*()
parameter being treated as unsigned.  The *printf() specifiers b/o/x/X
already do this (although the manual doesn't say that either, only for %u).

After looking through the comments for `dechex()`, there's another thing: 32-
vs 64-bit.  On a 64-bit system, I think dechex(-123) would currently return
ffffffffffffff85, which when reversed on my system gives

php -d precision=20 -r "var_dump(hexdec('ffffffffffffff85'));"
float(18446744073709552000)

Are you saying, Michael, that the negative behavior should be left as-is for
people to see "how the number is stored by the computer?"  I think just
using the *printf() specifiers would better.  IMO, the dec*() and *dec()
functions should work the same as the corresponding to/from base with
 `base_convert()` (absolute value), and vice-versa.

BTW, can `base_convert()` simply return an actual number instead of a string
when tobase=10?  Again, to be the same as *dec() and avoid conversion to
string if it's just going to be used in numeric context.


Matt


----- Original Message -----
From: "Michael Wallner"
Sent: Thursday, July 27, 2006


> Matt W wrote:
>
> > […]
>
> For your computer 0xffffff85 is -123 and 4294967173.  It's just how
> you look on it.
>
> > […]
>
> No way. Why should hexdec(dechex(-123)) return +123?
>
> --
> Michael

---

## #25050 — Matt W — 2006-07-29T09:45:50+00:00

URL: https://externals.io/message/24981#25050 · In reply to: #25032

Hi again,

OK, after my last message, I found when the dec*() functions started
converting to unsigned long (Bug #6761).  To make dechex(~8) etc. work.  Now
I know that behavior can't change. :-)  Hopefully this is my last e-mail
about this, if I can please find out about 2 simple things:

1) How should a negative *double*, whether it's < LONG_MIN or typecast
(double) -123, be handled?
*) Continue converting to long/unsigned long, like now?
*) Use absolute value? (Only if double!)

Either way, `base_convert()` should continue to use absolute value for all
numbers, I assume.

2) CAN `base_convert()` be changed to return an actual number instead of a
string if tobase=10?  Seems a waste to convert a base 10 result to string
like now... :-?


Thanks!
Matt


----- Original Message -----
From: "Matt W"
Sent: Friday, July 28, 2006


> Hi,
>
> More thoughts...
>
> I forgot to say last time that the manual doesn't mention the dec*()
> parameter being treated as unsigned.  The *printf() specifiers b/o/x/X
> already do this (although the manual doesn't say that either, only for
%u).
>
> After looking through the comments for `dechex()`, there's another thing:
32-
> vs 64-bit.  On a 64-bit system, I think dechex(-123) would currently
return
> ffffffffffffff85, which when reversed on my system gives
>
> php -d precision=20 -r "var_dump(hexdec('ffffffffffffff85'));"
> float(18446744073709552000)
>
> Are you saying, Michael, that the negative behavior should be left as-is
for
> people to see "how the number is stored by the computer?"  I think just
> using the *printf() specifiers would better.  IMO, the dec*() and *dec()
> functions should work the same as the corresponding to/from base with
> `base_convert()` (absolute value), and vice-versa.
>
> BTW, can `base_convert()` simply return an actual number instead of a string
> when tobase=10?  Again, to be the same as *dec() and avoid conversion to
> string if it's just going to be used in numeric context.
>
>
> Matt
