How to duplicate a floating point number in Ruby Sketchup?

I need to duplicate a set of floating-point number variables.
See below for example:
x, y, z = 1.1, 2.2, 3.3
a = [[x.dup, x.dup, x.dup],[y.dup, y.dup, y.dup], [z.dup, z.dup, z.dup]]

This exact code works in Ruby itself, however in Sketchup, within the ruby console, this returns the following:
Error: #<TypeError: can't dup Float>

I have also tried .clone and that returns basically the same thing.

My reason for wanting to duplicate is so that if I run the following equation:
a[0][1], a[1][1], a[2][1] = a[0][1]+1.1, a[1][1]+1.1, a[2][1]+1.1
The results should be:
a == [[1.1, 2.2, 1.1],[2.2, 3.3, 2.2], [3.3, 4.4, 3.3]]
x == 1.1
y == 2.2
z == 3.3

Is there any way around this?

What I was actually trying to do is this:
x, y, z = [1.1, 2.2, 3.3], [4.4, 5.5, 6.6], [7.7, 8.8, 9.9]
a = [x.dup, y.dup, z.dup]

And the results should be:
a == [[1.1, 3.3, 3.3], [4.4, 6.6, 6.6], [7.7, 9.9, 9.9]]
x == [1.1, 2.2, 3.3]
y == [4.4, 5.5, 6.6]
z == [7.7, 8.8, 9.9]

I worked out how to do this:
Once x,y & z are assigned, I did the following:
a = [x,y,z]]! { |r| r.dup.tap { |r2| r2[1] += 1.1 } }

EDIT: While this comes close, its still not right. The final result is:
[[1.1, 3.3000000000000003, 3.3], [4.4, 6.6, 6.6], [7.7, 9.9, 9.9]]

Anyone know what the problem is?

Okay, where did b come from ?

Thanks…noted and edited. Was using my example, and my real code together :flushed:

It does not actually work in Ruby itself. Ie, … if you read the documentation for the Float class, you’ll realize it is a set of objects. (The class has next_float and prev_float methods.)

irb(main):001:0> n= 1.1
=> 1.1
irb(main):002:0> n.class
=> Float
irb(main):003:0> n2 = n.dup
=> 1.1
irb(main):004:0> n2.class
=> Float
irb(main):005:0> n == n2
=> true
irb(main):006:0> n.object_id == n2.object_id
=> true

So there is no actually duplication. the reference n is pointing at the same Float object that the reference n2 is made to point at. Ruby has object references. It does not have variables like other languages that each “hold” independent values. Ruby is 100% object oriented. Everything in Ruby is either an operator, an object, or a reference that points at an object.

So again …

n2 = n.dup

… does the same thing as …

n2 = n

In Ruby, the = is the reference assignment operator. The statement above reads …
“Let the reference n2 be assigned to point at the object that the reference n is pointing at.”

If you wish further proof …


Returns the receiver.

So new for very recent Ruby versions (it is in Ruby 2.5.1+ used by SketchUp 2019+,) the Ruby Core overrode Object#dup and Object#clone for all numeric subclasses, so that code could happily use the same code for immediate and non-immediate classes. (“happily” means the suppression of the error.)

Duly noted. If you take a look out my corrected question, you will see that x,y, and z are now floating point arrays (What I am actually working with). I then nest these arrays in a new variable, which is when I begin to have trouble.

I seriously need an editor to make sure I actually have my question right first :face_with_hand_over_mouth:

Yea but you corrected that original error, so it doesn’t make sense as a question about an error (anymore.)

So the goal was to leave the arrays x, y and z unchanged. You could also do …

a = [x.dup, y.dup, z.dup].each {|ary| ary[1]+=1.1 }
1 Like

still stuffs up with the value 3.3 (it returns 3.3000000000000003 in Sketchup Ruby (and Ruby+) and Ruby itself)
Is this for me only or for you too?

Also with the editing of questions, should I have left it and put an edited question down below the original question?

This is explained here: Is Floating Point Math Broken? | Stack Exchange

So thanks heaps @DanRathbun !!

1 Like

I’m not seeing that error…

x, y, z = [1.1, 2.2, 3.3], [4.4, 5.5, 6.6], [7.7, 8.8, 9.9]
#> [[1.1, 2.2, 3.3], [4.4, 5.5, 6.6], [7.7, 8.8, 9.9]]
#> [1.1, 2.2, 3.3]
#> [4.4, 5.5, 6.6]
#> [7.7, 8.8, 9.9]
a = [x.dup, y.dup, z.dup]
#> [[1.1, 2.2, 3.3], [4.4, 5.5, 6.6], [7.7, 8.8, 9.9]]
#> 1391516234980
#> 1391516234880
#> 1391516234800
#> [1391514853300, 1391514853220, 1391514853200]
a[0][1], a[1][1], a[2][1] = a[0][1]+1.1, a[1][1]+1.1, a[2][1]+1.1
#> [3.3000000000000003, 6.6, 9.9]
#> [[1.1, 3.3000000000000003, 3.3], [4.4, 6.6, 6.6], [7.7, 9.9, 9.9]]

Yes you should have left it, because the topic thread makes no sense now and the snippet is confusing … evidence why Thomas doesn’t see an error …
EDIT: OP has since restored the 1st post to the original question with the “erroneous snippets”.

Because he edited the original post and changed the snippet so it doesn’t have the error.

His original snippet was attempting to duplicate a Float object directly (instead of the nested arrays holding the floats.) Ie … his snippet was originally …

x, y, z = 1.1, 2.2, 3.3
a = [[x.dup, x.dup, x.dup],[y.dup, y.dup, y.dup], [z.dup, z.dup, z.dup]]

As I said (above) the Ruby Core added override methods sometime after Ruby 2.2.4, and before 2.5.1, to the Numeric class for #clone and #dup that just returns self.
Before this the "can't dup Float" TypeError shown would be raised. (Ie, in SketchUp versions less than 19.)

Yes I see it also. The nature of Floats on computers.

1 Like

Ah, right. I am using 2017. Thanks for pointing this out…also thanks for the answer as to changing my question.

1 Like

I don’t really get the question. Floats, and to my knowledge Lengths, are immutable. Duplicating such an object doesn’t make much sense as the object can’t be modified anyway. Why do you want to duplicate it in the first place?

Okay, I cant even work out how i got my original error, because you don’t need to duplicate a simple assignment, and its possible to duplicate an array…sorry for the waste of time i guess?

I must have either been having a bad day or my computer was (highly likely it was me :grin:)

I’m assuming that you had an array of arrays and got caught by that .dup/.clone does’t deep-dup/clone. Happens easily. And something to consider when you write a class that takes input parameters and assigns it to an instance variable. The caller might not want the data passed in to be mutated and you might want to consider storing a copy of the input data.

1 Like