3

I'm likely missing something simple here, so I apologize in advance. I am also aware that there is likely a better approach to this, so I'm open to that as well.

I'm trying to run a PowerShell script that will look at an array of values, comparing them to see the value of the difference between two elements of an array.

Below is a sample data set I'm using to test with that is imported into powershell from CSV:

1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.7, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.7, 2.9, 3.0

What I'm trying to accomplish is running through this list and comparing the second entry with the first, the third with the second, fourth with the third, etc, adding the element to $export ONLY if it has a value that is at least 0.2 greater than the previous element.

Here's what I've tried:

$import = get-content C:/pathtoCSVfile
$count = $import.Length-1;
$current=0;

Do 
{    
    $current=$current+1;
    $previous=$current-1

    if (($import[$current]-$import[$previous]) -ge 0.2)
    {
        $export=$export+$import[$current]+"`r`n";
    }
} 
until ($current -eq $count)

Now I've run this with Trace on and it assigns values to $current and $previous and runs the subtraction of the two as described in the if condition on each loop through, but ONLY for the value of 2.7 ($import[14]-$import[13]) is it registering that the if condition has been met, thus leaving only a single value of 2.7 in $export. I expected other values (1.7, 1.9, and 2.9) to also be added to the $export variable.

Again, this is probably something stupid/obvious I'm overlooking, but I can't seem to figure it out. Thanks in advance for any insight you can offer.

3
  • Is $export a scalar value or an array? Define $export = @() if it is an array. Commented Jun 17, 2018 at 20:06
  • A core problem is that $import is a string and not an array. Commented Jun 17, 2018 at 20:15
  • @lit: Unless C:/pathtoCSVfile happens to contain just 1 line, the output from get-content C:/pathtoCSVfile is an array (of lines). As written, $export builds up a single, multi-line [string] instance. Commented Jun 17, 2018 at 21:01

1 Answer 1

6

The problem is that decimal fractions have no exact representation in the implicitly used [double] data type, resulting in rounding errors that cause your -ge 0.2 comparison to yield unexpected results.

A simple example with [double] values, which are what PowerShell implicitly uses with number literals that have a decimal point:

PS> 2.7 - 2.5 -ge 0.2
True  # OK, but only accidentally so, due to the specific input numbers.

PS> 1.7 - 1.5 -ge 0.2
False  # !! Due to the inexact internally binary [double] representation.

If you force your calculations to use the [decimal] type instead, the problem goes away.

Applied to the above example (appending d to a number literal in PowerShell makes it a [decimal]):

PS> 1.7d - 1.5d -ge 0.2d
True # OK - Comparison is now exact, due to [decimal] values.

Applied in the context of a more PowerShell-idiomatic reformulation of your code:

# Sample input; note that floating-point number literals such as 1.0 default to [double]
# Similarly, performing arithmetic on *strings* that look like floating-point numbers
# defaults to [double], and Import-Csv always creates string properties.
$numbers = 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.7, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.7, 2.9, 3.0

# Collect those array elements that are >= 0.2 than their preceding element
# in output *array* $exports.
$exports = foreach ($ndx in 1..($numbers.Count - 1)) {
  if ([decimal] $numbers[$ndx] - [decimal] $numbers[$ndx-1] -ge 0.2d) {
    $numbers[$ndx] 
  }
}

# Output the result array.
# To create a multi-line string representation, use $exports -join "`r`n"
$exports

The above yields:

1.7
1.9
2.7
2.9
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.