Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add specifications for rule GCI99, this rule concerns the different ways of squaring a value.

### Changed

- Correction of various typos in rules documentations
Expand Down
1 change: 1 addition & 0 deletions RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Some are applicable for different technologies.
| GCI92 | Use string.Length instead of comparison with empty string | Comparing a string to an empty string is unnecessary and can be replaced by a call to `string.Length` which is more performant and more readable. | | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | ✅ | 🚫 |
| GCI93 | Return `Task` directly | Consider returning a `Task` directly instead of a single `await` | | ❓ | ❓ | ❓ | ❓ | ❓ | ✅ | ❓ |
| GCI94 | Use orElseGet instead of orElse | Parameter of orElse() is evaluated, even when having a non-empty Optional. Supplier method of orElseGet passed as an argument is only executed when an Optional value isn’t present. Therefore, using orElseGet() will save computing time. | [Optimized use of Java Optional Else](https://github.com/green-code-initiative/creedengo-challenge/issues/77) | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 |
| GCI99 | OptimizeSquareComputation | In Python, if you want to square x, you can do x*x or x**2. | | ❓ | ❓ | ❓ | ✅ | ❓ | ❓ | ❓ |
| GCI203 | Detect unoptimized file formats | When it is possible, to use svg format image over other image format | | 🚧 | 🚀 | 🚀 | ✅ | 🚀 | 🚀 | 🚫 |
| GCI404 | Avoid list comprehension in iterations | Use generator comprehension instead of list comprehension in for loop declaration | | 🚫 | 🚫 | 🚫 | ✅ | 🚫 | 🚫 | 🚫 |
| GCI522 | Sobriety: Brightness Override | To avoid draining the battery, iOS and Android devices adapt the brightness of the screen depending on the environment light. | | 🚫 | 🚫 | ✅ | 🚫 | 🚫 | 🚫 | 🚫 |
Expand Down
16 changes: 16 additions & 0 deletions src/main/rules/GCI99/GCI99.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"title": "Use multiplication instead of math.pow() or exponentiation",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "1min"
},
"tags": [
"creedengo",
"eco-design",
"performance"
],
"defaultSeverity": "Minor"
}

96 changes: 96 additions & 0 deletions src/main/rules/GCI99/python/GCI99.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
In Python, if you want to square x, you can do x*x or x**2.
At a lower level, these are two different instructions for the CPU
This rule will also be relevant for higher powers, but for reasons of readability and occurrence, the squaring rule remains the most relevant.

== Non compliant Code Example

[source,python]
----
x = x**2
# or
x = math.pow(x,2)
----

== Compliant Solution

[source,python]
----
x = x*x
----

== Relevance Analysis

The following results were obtained through local experiments.

=== Configuration

* Processor: Intel(R) Core(TM) Ultra 5 135U, 2100 MHz, 12 cores, 14 logical processors
* RAM: 16 GB
* CO2 Emissions Measurement: Using CodeCarbon

=== Context

This rule is based on the fact that to perform the calculation x², there are different ways of doing it in Python. The most common method is x**2, which at compile time is translated into BINARY_POWER, resulting in additional floating-point and logarithmic calculations.

This is due to the internal implementation of exponentiation in Python, often based on the identity:
```python
x**y = exp(y * log(x))
```
This allows general handling of edge cases (negative values, floats, etc.), but makes it heavier than direct multiplication. In contrast, x * x is compiled into BINARY_MULTIPLY, a direct and efficient CPU instruction.

By contrast, x * x is compiled to BINARY_MULTIPLY, which corresponds to a single, simple CPU instruction.

Finally, math.pow adds further overhead due to function calls and type conversions.

*lambda x: x * x*
[source,bytecode]
----
0 LOAD_FAST 0 (x)
2 LOAD_FAST 0 (x)
4 BINARY_MULTIPLY
6 RETURN_VALUE
----

The program loads x twice, runs BINARY_MULTIPLY and returns the result.

lambda x: math.pow(x, 2)
[source,bytecode]
----
0 LOAD_GLOBAL 0 (math)
2 LOAD_ATTR 1 (pow)
4 LOAD_FAST 0 (x)
6 LOAD_CONST 1 (2)
8 CALL_FUNCTION 2
10 RETURN_VALUE
----

First, the math module is loaded into the global space, then the pow attribute, the two arguments are loaded, the pow function is called and the value is returned.

lambda x: x ** 2
[source,bytecode]
----
0 LOAD_FAST 0 (x)
2 LOAD_CONST 1 (2)
4 BINARY_POWER
6 RETURN_VALUE
----

The program loads x, and the constant 2, runs BINARY_POWER, and returns the value.

To compare the three calculation techniques, we will compare their emissions by applying the calculation while varying the number of affected lines.

=== Impact Analysis

It gives us the following results:

*1. Carbon emissions during writing:*

image::image.png[]

=== Conclusion

the rule is relevant, it also applies to the case where the user wishes to set his variable to power 3, 4 etc... but in this case we'll lose visibility. Since the sqaure is the most widely used, this rule applies only to it.

=== References

https://chrissardegna.com/blog/python-expontentiation-performance/
Binary file added src/main/rules/GCI99/python/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.