radon icon indicating copy to clipboard operation
radon copied to clipboard

Incorrect number of distinct operators in Halstead metric

Open rdbliss opened this issue 5 years ago • 4 comments

While trying to fix #160, I noticed that the Halstead visitor counts operands incorrectly. Essentially, it states that every expression that an operator is applied to is a distinct operator. For example, in the current master,

def f(x):
    x + x + x

has two distinct operands. These are x and x + x.

The problem is that the operator visitors claim to know what operands they are being applied to. In x + (x + x), the first + claims to apply to x and (x + x), and treats (x + x) as an actual operand. I believe that Halstead only ever meant variables as operands, not arbitrary expressions containing them.

I believe that this can be fixed by forcing every visitor method to ignore operands entirely and implementing a visit_Name method. I tried this in a quick experiment, and it fixes the above example. It also gives more reasonable results when combined with the visit_Assignment method requested in #160.

rdbliss avatar Nov 27 '18 21:11 rdbliss

Hi @rwbogl, I'm very sorry for the long delay. Do you happen to still have the code for this? I have been fixing a lot of issues and I'd like to close these two as well. You are welcome to open a PR!

rubik avatar Jan 26 '19 13:01 rubik

https://www.geeksforgeeks.org/software-engineering-halsteads-software-metrics/

from Software Engineering | Halstead’s Software Metrics .... Counting rules for C language – ...

  1. Comments are not considered.
  2. The identifier and function declarations are not considered
  3. All the variables and constants are considered operands.
  4. Global variables used in different modules of the same program are counted as multiple occurrences of the same variable.
  5. Local variables with the same name in different functions are counted as unique operands.
  6. Functions calls are considered as operators.
  7. All looping statements e.g., do {…} while ( ), while ( ) {…}, for ( ) {…}, all control statements e.g., if ( ) {…}, if ( ) {…} else {…}, etc. are considered as operators.
  8. In control construct switch ( ) {case:…}, switch as well as all the case statements are considered as operators.
  9. The reserve words like return, default, continue, break, sizeof, etc., are considered as operators.
  10. All the brackets, commas, and terminators are considered as operators.
  11. GOTO is counted as an operator and the label is counted as an operand.
  12. The unary and binary occurrence of “+” and “-” are dealt separately. Similarly “*” (multiplication operator) are dealt separately.
  13. In the array variables such as “array-name [index]” “array-name” and “index” are considered as operands and [ ] is considered as operator.
  14. In the structure variables such as “struct-name, member-name” or “struct-name -> member-name”, struct-name, member-name are taken as operands and ‘.’, ‘->’ are taken as operators. Some names of member elements in different structure variables are counted as unique operands.
  15. All the hash directive are ignored.

int sort (int x[ ], int n)

{ int i, j, save, im1; /This function sorts array x in ascending order / If (n< 2) return 1; for (i=2; i< =n; i++) { im1=i-1; for (j=1; j< =im1; j++) if (x[i] < x[j]) { Save = x[i]; x[i] = x[j]; x[j] = save; } } return 0; } Therefore, N = 91 n = 24 V = 417.23 bits N^ = 86.51 n2 = 3 (x:array holding integer to be sorted. This is used both as input and output) V = 11.6 L = 0.027 D = 37.03 L^ = 0.038 T = 610 seconds

def sort(X,n): if n<2: return 1 for i in range(0,n): im=i for j in range(im,n): print(i,j) if X[i]>X[j]: print('troca',X) X[i],X[j]=X[j],X[i] return 0 V=[3,7,1,3,5,7,2];sort(V,len(V));print(V);exit(1)
(True, {'loc': 12, 'lloc': 15, 'sloc': 11, 'h1': 2, 'h2': 4, 'N1': 2, 'N2': 4, 'vocab': 6, 'len': 6, 'calc_len': 10.0, 'vol': 15.51, 'diffic': 1.0, 'effort': 15.51, 'time': 0.86})

Comparing the halstead´s numbers of C and Python codes for the same function the differences are very discrepant, they deserve a review. grateful for the attention.

eloifavero avatar Mar 20 '21 14:03 eloifavero

@eloifavero The code above is quite difficult to read. Also, I am not sure those two implementations can be compared because they are quite a lot different. If you post them with proper indentation and syntax highlighting I'll be happy to take a look.

rubik avatar May 17 '21 13:05 rubik

I'm curious about that, so I'm going to take the code from the source and try touching it up myself.

int sort (int x[ ], int n)

{
    int i, j, save, im1;
    /*This function sorts array x in ascending order */
    If (n< 2) return 1;
    for (i=2; i< =n; i++)
    {
        im1=i-1;
        for (j=1; j< =im1; j++)
            if (x[i] < x[j])
            {
                Save = x[i];
                x[i] = x[j];
                x[j] = save;
            }
    }
    return 0;
}
def sort_translated(x, n):
    if n < 2:
        return 1
    for i in range(2, n + 1):
        im1 = i - 1
        for j in range(1, im1 + 1):
            if x[i] < x[j]:
                save = x[i]
                x[i] = x[j]
                x[j] = save
    return 0


def sort_more_idiomatic(x, n):
    if n < 2:
        return 1
    for i in range(2, n + 1):
        for j in range(1, i):
            if x[i] < x[j]:
                x[i], x[j] = x[j], x[i]
    return 0

mwchase avatar May 11 '22 14:05 mwchase