Unidata / UDUNITS-2

API and utility for arithmetic manipulation of units of physical quantities
http://www.unidata.ucar.edu/software/udunits
Other
59 stars 36 forks source link

Unable to scale by 0 #117

Open Enchufa2 opened 1 year ago

Enchufa2 commented 1 year ago

Scaling by 0 gives:

ut_scale(0, unit)
#> ut_scale(): NULL factor argument

I think this should work. Or how are we supposed to get 0 units?

semmerson commented 1 year ago

Hi Iñaki Ucar,

There's no such thing as a zero unit. There is the dimensionless unit "1", however.

Enchufa2 commented 1 year ago

So there's no way to represent 0 m? Or, fot that matter, 0 ºC? But converting 273.15 K to ºC works, so... I'm a bit confused here. :)

semmerson commented 1 year ago

@Enchufa2 In your example, the "m" is the unit and is finite. The "0" is the amount.

Enchufa2 commented 1 year ago

Correct. And parsing "0 ºC" does not work with the "NULL factor argument" above. But parsing "273.15 K" does work. I just don't understand why a factor equal to 0 is special here in any way. Probably because I don't know udunits' internals, but still, as a user of the API, this is very confusing. And the documentation says nothing about this, just that it "returns a unit equivalent to another unit scaled by a numeric factor".

For context, here we have a function where two vectors of numbers, with two different units, are compared. Particularly, it feels natural to just do this:

  ut_unit *ux = ut_parse(sys, ut_trim(xn[0], enc), enc);
  ut_unit *uy = ut_parse(sys, ut_trim(yn[0], enc), enc);

  for (int i=0, j=0; i < x.size(); i++, j++) {
    if (j == y.size())
      j = 0;
    out[i] = ut_compare(ut_scale(x[i], ux), ut_scale(y[j], uy));
  }

I.e., units xn and yn, for vectors x and y respectively, are parsed once, and then scaled and compared by every element in those vectors (with index recycling). Let's forget that I'm not freeing the output of ut_scale and I should, but otherwise, this works for any factor except for 0.

Enchufa2 commented 1 year ago

Also for reference, I'm currently applying this fix, because, admittedly, if one unit is equal to 0, then you don't need the unit to compare them. But this works if units are not compatible, when it shouldn't. And in general it's unintuitive, and having to apply this exception doesn't feel right.

Enchufa2 commented 1 year ago

I found an issue also when the factor is equal to 1. This line of R code calls the code linked above:

units:::ud_compare(0.5, c(0.9, 1, 2), "m", "m")
#> [1] -1  1 -1

and as you can see, 0.5 m is considered greater than 1 m (!). Please, let me know if you want me to open a new issue for this.

Enchufa2 commented 1 year ago

The issue here may be that I don't think that ut_compare works as I expect...

units:::ud_compare(0.5, c(-0.1, 1, 2)*39.3701, "m", "inch")
#> [1] -1 -1 -1

This is weird to me. It means basically that ut_compare is not meant to compare quantities, but just "unit objects", whatever it means? And then I don't understand what's the ordering. I thought that this was for comparing quantities when the use of ut_compare was suggested in this issue. So I'm a bit lost now.