void remove_point_from_cluster(unsigned int cluster_ind, double *CX,
                               const double *px, double pw,
                               unsigned int *nr_points, double *CW,
                               unsigned int dim) {
  double *pcx = CX + cluster_ind * dim;
  if (nr_points[cluster_ind] < 2) {
    for (unsigned int k = 0; k < dim; k++)
      pcx[k] = 0.0;
    nr_points[cluster_ind] = 0;
    CW[cluster_ind] = 0;
  } else {
    double cw_old, cw_new;
    cw_old = CW[cluster_ind];
    (nr_points[cluster_ind])--;
    CW[cluster_ind] -= pw;
    cw_new = CW[cluster_ind];
    for (unsigned int k = 0; k < dim; k++)
      pcx[k] = (cw_old * pcx[k] - pw * px[k]) / cw_new;
  }
}


x86 assembly (clang, -O0):
<remove_point_from_cluster>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0x4(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
movsd  %xmm0,-0x20(%rbp)
mov    %rcx,-0x28(%rbp)
mov    %r8,-0x30(%rbp)
mov    %r9d,-0x34(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x4(%rbp),%ecx
imul   -0x34(%rbp),%ecx
mov    %ecx,%ecx
shl    $0x3,%rcx
add    %rcx,%rax
mov    %rax,-0x40(%rbp)
mov    -0x28(%rbp),%rax
mov    -0x4(%rbp),%ecx
cmpl   $0x2,(%rax,%rcx,4)
jae    119b <remove_point_from_cluster+0x9b>
movl   $0x0,-0x44(%rbp)
mov    -0x44(%rbp),%eax
cmp    -0x34(%rbp),%eax
jae    1179 <remove_point_from_cluster+0x79>
mov    -0x40(%rbp),%rax
mov    -0x44(%rbp),%ecx
xorps  %xmm0,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x44(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x44(%rbp)
jmp    1150 <remove_point_from_cluster+0x50>
mov    -0x28(%rbp),%rax
mov    -0x4(%rbp),%ecx
movl   $0x0,(%rax,%rcx,4)
mov    -0x30(%rbp),%rax
mov    -0x4(%rbp),%ecx
xorps  %xmm0,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
jmp    125f <remove_point_from_cluster+0x15f>
mov    -0x30(%rbp),%rax
mov    -0x4(%rbp),%ecx
movsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x50(%rbp)
mov    -0x28(%rbp),%rax
mov    -0x4(%rbp),%ecx
mov    (%rax,%rcx,4),%edx
add    $0xffffffff,%edx
mov    %edx,(%rax,%rcx,4)
movsd  -0x20(%rbp),%xmm1
mov    -0x30(%rbp),%rax
mov    -0x4(%rbp),%ecx
movsd  (%rax,%rcx,8),%xmm0
subsd  %xmm1,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x30(%rbp),%rax
mov    -0x4(%rbp),%ecx
movsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x58(%rbp)
movl   $0x0,-0x5c(%rbp)
mov    -0x5c(%rbp),%eax
cmp    -0x34(%rbp),%eax
jae    125a <remove_point_from_cluster+0x15a>
movsd  -0x50(%rbp),%xmm0
mov    -0x40(%rbp),%rax
mov    -0x5c(%rbp),%ecx
movsd  (%rax,%rcx,8),%xmm2
movsd  -0x20(%rbp),%xmm1
mov    -0x18(%rbp),%rax
mov    -0x5c(%rbp),%ecx
mulsd  (%rax,%rcx,8),%xmm1
movq   %xmm1,%rax
movabs $0x8000000000000000,%rcx
xor    %rcx,%rax
movq   %rax,%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
divsd  -0x58(%rbp),%xmm0
mov    -0x40(%rbp),%rax
mov    -0x5c(%rbp),%ecx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x5c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x5c(%rbp)
jmp    11ee <remove_point_from_cluster+0xee>
jmp    125f <remove_point_from_cluster+0x15f>
pop    %rbp
ret

x86 assembly (clang, -O2):
<remove_point_from_cluster>:
push   %r15
push   %r14
push   %rbx
mov    %r8,%r14
mov    %rcx,%r15
mov    %edi,%eax
mov    %r9d,%r8d
imul   %edi,%r8d
lea    (%rsi,%r8,8),%rdi
mov    %eax,%ebx
mov    (%rcx,%rbx,4),%eax
cmp    $0x1,%eax
ja     115a <remove_point_from_cluster+0x4a>
test   %r9d,%r9d
je     1145 <remove_point_from_cluster+0x35>
mov    %r9d,%edx
shl    $0x3,%rdx
xor    %esi,%esi
call   1030 <memset@plt>
movl   $0x0,(%r15,%rbx,4)
movq   $0x0,(%r14,%rbx,8)
jmp    1310 <remove_point_from_cluster+0x200>
movsd  (%r14,%rbx,8),%xmm1
add    $0xffffffff,%eax
mov    %eax,(%r15,%rbx,4)
movapd %xmm1,%xmm2
subsd  %xmm0,%xmm2
movsd  %xmm2,(%r14,%rbx,8)
test   %r9d,%r9d
je     1310 <remove_point_from_cluster+0x200>
mov    %r9d,%r10d
cmp    $0x1,%r9d
je     11a5 <remove_point_from_cluster+0x95>
lea    (%rdx,%r10,8),%rax
cmp    %rax,%rdi
jae    123f <remove_point_from_cluster+0x12f>
lea    (%r10,%r8,1),%rax
lea    (%rsi,%rax,8),%rax
cmp    %rdx,%rax
jbe    123f <remove_point_from_cluster+0x12f>
xor    %eax,%eax
mov    %rax,%rcx
not    %rcx
test   $0x1,%r10b
je     11d6 <remove_point_from_cluster+0xc6>
movsd  (%rdx,%rax,8),%xmm3
mulsd  %xmm0,%xmm3
movsd  (%rdi,%rax,8),%xmm4
mulsd  %xmm1,%xmm4
subsd  %xmm3,%xmm4
divsd  %xmm2,%xmm4
movsd  %xmm4,(%rdi,%rax,8)
or     $0x1,%rax
add    %r10,%rcx
je     1310 <remove_point_from_cluster+0x200>
lea    (%rsi,%r8,8),%rcx
add    $0x8,%rcx
nopw   0x0(%rax,%rax,1)
movsd  (%rdx,%rax,8),%xmm3
mulsd  %xmm0,%xmm3
movsd  -0x8(%rcx,%rax,8),%xmm4
mulsd  %xmm1,%xmm4
subsd  %xmm3,%xmm4
divsd  %xmm2,%xmm4
movsd  %xmm4,-0x8(%rcx,%rax,8)
movsd  0x8(%rdx,%rax,8),%xmm3
mulsd  %xmm0,%xmm3
movsd  (%rcx,%rax,8),%xmm4
mulsd  %xmm1,%xmm4
subsd  %xmm3,%xmm4
divsd  %xmm2,%xmm4
movsd  %xmm4,(%rcx,%rax,8)
add    $0x2,%rax
cmp    %rax,%r10
jne    11f0 <remove_point_from_cluster+0xe0>
jmp    1310 <remove_point_from_cluster+0x200>
mov    %r10d,%eax
and    $0xfffffffe,%eax
movapd %xmm0,%xmm4
unpcklpd %xmm0,%xmm4
movapd %xmm1,%xmm3
unpcklpd %xmm1,%xmm3
movapd %xmm2,%xmm8
unpcklpd %xmm2,%xmm8
lea    -0x2(%rax),%rcx
mov    %rcx,%r9
shr    %r9
add    $0x1,%r9
test   %rcx,%rcx
je     1316 <remove_point_from_cluster+0x206>
mov    %r9,%rbx
and    $0xfffffffffffffffe,%rbx
lea    (%rsi,%r8,8),%r11
add    $0x10,%r11
xor    %ecx,%ecx
nopw   0x0(%rax,%rax,1)
movupd (%rdx,%rcx,8),%xmm6
mulpd  %xmm4,%xmm6
movupd -0x10(%r11,%rcx,8),%xmm7
movupd (%r11,%rcx,8),%xmm5
mulpd  %xmm3,%xmm7
subpd  %xmm6,%xmm7
divpd  %xmm8,%xmm7
movupd %xmm7,-0x10(%r11,%rcx,8)
movupd 0x10(%rdx,%rcx,8),%xmm6
mulpd  %xmm4,%xmm6
mulpd  %xmm3,%xmm5
subpd  %xmm6,%xmm5
divpd  %xmm8,%xmm5
movupd %xmm5,(%r11,%rcx,8)
add    $0x4,%rcx
add    $0xfffffffffffffffe,%rbx
jne    1290 <remove_point_from_cluster+0x180>
test   $0x1,%r9b
je     1307 <remove_point_from_cluster+0x1f7>
movupd (%rdi,%rcx,8),%xmm5
movupd (%rdx,%rcx,8),%xmm6
mulpd  %xmm6,%xmm4
mulpd  %xmm5,%xmm3
subpd  %xmm4,%xmm3
divpd  %xmm8,%xmm3
movupd %xmm3,(%rdi,%rcx,8)
cmp    %r10,%rax
jne    11a7 <remove_point_from_cluster+0x97>
pop    %rbx
pop    %r14
pop    %r15
ret
xor    %ecx,%ecx
test   $0x1,%r9b
jne    12e7 <remove_point_from_cluster+0x1d7>
jmp    1307 <remove_point_from_cluster+0x1f7>

LLVM IR (-O0):
define void @remove_point_from_cluster(i32 %0, double* %1, double* %2, double %3, i32* %4, double* %5, i32 %6) {
%8 = alloca i32
%9 = alloca double*
%10 = alloca double*
%11 = alloca double
%12 = alloca i32*
%13 = alloca double*
%14 = alloca i32
%15 = alloca double*
%16 = alloca i32
%17 = alloca double
%18 = alloca double
%19 = alloca i32
store i32 %0, i32* %8
store double* %1, double** %9
store double* %2, double** %10
store double %3, double* %11
store i32* %4, i32** %12
store double* %5, double** %13
store i32 %6, i32* %14
%20 = load double*, double** %9
%21 = load i32, i32* %8
%22 = load i32, i32* %14
%23 = mul i32 %21, %22
%24 = zext i32 %23 to i64
%25 = getelementptr inbounds double, double* %20, i64 %24
store double* %25, double** %15
%26 = load i32*, i32** %12
%27 = load i32, i32* %8
%28 = zext i32 %27 to i64
%29 = getelementptr inbounds i32, i32* %26, i64 %28
%30 = load i32, i32* %29
%31 = icmp ult i32 %30, 2
br i1 %31, label %32, label %54
32: ; preds = %7
store i32 0, i32* %16
br label %33
33: ; preds = %42, %32
%34 = load i32, i32* %16
%35 = load i32, i32* %14
%36 = icmp ult i32 %34, %35
br i1 %36, label %37, label %45
37: ; preds = %33
%38 = load double*, double** %15
%39 = load i32, i32* %16
%40 = zext i32 %39 to i64
%41 = getelementptr inbounds double, double* %38, i64 %40
store double 0.000000e+00, double* %41
br label %42
42: ; preds = %37
%43 = load i32, i32* %16
%44 = add i32 %43, 1
store i32 %44, i32* %16
br label %33
45: ; preds = %33
%46 = load i32*, i32** %12
%47 = load i32, i32* %8
%48 = zext i32 %47 to i64
%49 = getelementptr inbounds i32, i32* %46, i64 %48
store i32 0, i32* %49
%50 = load double*, double** %13
%51 = load i32, i32* %8
%52 = zext i32 %51 to i64
%53 = getelementptr inbounds double, double* %50, i64 %52
store double 0.000000e+00, double* %53
br label %108
54: ; preds = %7
%55 = load double*, double** %13
%56 = load i32, i32* %8
%57 = zext i32 %56 to i64
%58 = getelementptr inbounds double, double* %55, i64 %57
%59 = load double, double* %58
store double %59, double* %17
%60 = load i32*, i32** %12
%61 = load i32, i32* %8
%62 = zext i32 %61 to i64
%63 = getelementptr inbounds i32, i32* %60, i64 %62
%64 = load i32, i32* %63
%65 = add i32 %64, -1
store i32 %65, i32* %63
%66 = load double, double* %11
%67 = load double*, double** %13
%68 = load i32, i32* %8
%69 = zext i32 %68 to i64
%70 = getelementptr inbounds double, double* %67, i64 %69
%71 = load double, double* %70
%72 = fsub double %71, %66
store double %72, double* %70
%73 = load double*, double** %13
%74 = load i32, i32* %8
%75 = zext i32 %74 to i64
%76 = getelementptr inbounds double, double* %73, i64 %75
%77 = load double, double* %76
store double %77, double* %18
store i32 0, i32* %19
br label %78
78: ; preds = %104, %54
%79 = load i32, i32* %19
%80 = load i32, i32* %14
%81 = icmp ult i32 %79, %80
br i1 %81, label %82, label %107
82: ; preds = %78
%83 = load double, double* %17
%84 = load double*, double** %15
%85 = load i32, i32* %19
%86 = zext i32 %85 to i64
%87 = getelementptr inbounds double, double* %84, i64 %86
%88 = load double, double* %87
%89 = load double, double* %11
%90 = load double*, double** %10
%91 = load i32, i32* %19
%92 = zext i32 %91 to i64
%93 = getelementptr inbounds double, double* %90, i64 %92
%94 = load double, double* %93
%95 = fmul double %89, %94
%96 = fneg double %95
%97 = call double @llvm.fmuladd.f64(double %83, double %88, double %96)
%98 = load double, double* %18
%99 = fdiv double %97, %98
%100 = load double*, double** %15
%101 = load i32, i32* %19
%102 = zext i32 %101 to i64
%103 = getelementptr inbounds double, double* %100, i64 %102
store double %99, double* %103
br label %104
104: ; preds = %82
%105 = load i32, i32* %19
%106 = add i32 %105, 1
store i32 %106, i32* %19
br label %78
107: ; preds = %78
br label %108
108: ; preds = %107, %45
ret void
}

LLVM IR (-O2):
define void @remove_point_from_cluster(i32 %0, double* nocapture %1, double* nocapture %2, double %3, i32* nocapture %4, double* nocapture %5, i32 %6) {
%8 = mul i32 %6, %0
%9 = zext i32 %8 to i64
%10 = getelementptr double, double* %1, i64 %9
%11 = bitcast double* %10 to i8*
%12 = zext i32 %0 to i64
%13 = getelementptr inbounds i32, i32* %4, i64 %12
%14 = load i32, i32* %13
%15 = icmp ult i32 %14, 2
br i1 %15, label %16, label %23
16: ; preds = %7
%17 = icmp eq i32 %6, 0
br i1 %17, label %21, label %18
18: ; preds = %16
%19 = zext i32 %6 to i64
%20 = shl nuw nsw i64 %19, 3
br label %21
21: ; preds = %18, %16
store i32 0, i32* %13
%22 = getelementptr inbounds double, double* %5, i64 %12
store double 0.000000e+00, double* %22
br label %140
23: ; preds = %7
%24 = getelementptr inbounds double, double* %5, i64 %12
%25 = load double, double* %24
%26 = add i32 %14, -1
store i32 %26, i32* %13
%27 = fsub double %25, %3
store double %27, double* %24
%28 = icmp eq i32 %6, 0
br i1 %28, label %140, label %29
29: ; preds = %23
%30 = zext i32 %6 to i64
%31 = icmp eq i32 %6, 1
br i1 %31, label %100, label %32
32: ; preds = %29
%33 = add nuw nsw i64 %30, %9
%34 = getelementptr double, double* %1, i64 %33
%35 = getelementptr double, double* %2, i64 %30
%36 = icmp ult double* %10, %35
%37 = icmp ugt double* %34, %2
%38 = and i1 %36, %37
br i1 %38, label %100, label %39
39: ; preds = %32
%40 = and i64 %30, 4294967294
%41 = insertelement <2 x double> poison, double %3, i64 0
%42 = shufflevector <2 x double> %41, <2 x double> poison, <2 x i32> zeroinitializer
%43 = insertelement <2 x double> poison, double %25, i64 0
%44 = shufflevector <2 x double> %43, <2 x double> poison, <2 x i32> zeroinitializer
%45 = insertelement <2 x double> poison, double %27, i64 0
%46 = shufflevector <2 x double> %45, <2 x double> poison, <2 x i32> zeroinitializer
%47 = add nsw i64 %40, -2
%48 = lshr exact i64 %47, 1
%49 = add nuw i64 %48, 1
%50 = and i64 %49, 1
%51 = icmp eq i64 %47, 0
br i1 %51, label %83, label %52
52: ; preds = %39
%53 = and i64 %49, -2
br label %54
54: ; preds = %54, %52
%55 = phi i64 [ 0, %52 ], [ %80, %54 ]
%56 = phi i64 [ 0, %52 ], [ %81, %54 ]
%57 = getelementptr inbounds double, double* %10, i64 %55
%58 = bitcast double* %57 to <2 x double>*
%59 = load <2 x double>, <2 x double>* %58
%60 = getelementptr inbounds double, double* %2, i64 %55
%61 = bitcast double* %60 to <2 x double>*
%62 = load <2 x double>, <2 x double>* %61
%63 = fneg <2 x double> %62
%64 = fmul <2 x double> %42, %63
%65 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %44, <2 x double> %59, <2 x double> %64)
%66 = fdiv <2 x double> %65, %46
%67 = bitcast double* %57 to <2 x double>*
store <2 x double> %66, <2 x double>* %67
%68 = or i64 %55, 2
%69 = getelementptr inbounds double, double* %10, i64 %68
%70 = bitcast double* %69 to <2 x double>*
%71 = load <2 x double>, <2 x double>* %70
%72 = getelementptr inbounds double, double* %2, i64 %68
%73 = bitcast double* %72 to <2 x double>*
%74 = load <2 x double>, <2 x double>* %73
%75 = fneg <2 x double> %74
%76 = fmul <2 x double> %42, %75
%77 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %44, <2 x double> %71, <2 x double> %76)
%78 = fdiv <2 x double> %77, %46
%79 = bitcast double* %69 to <2 x double>*
store <2 x double> %78, <2 x double>* %79
%80 = add nuw i64 %55, 4
%81 = add nuw i64 %56, 2
%82 = icmp eq i64 %81, %53
br i1 %82, label %83, label %54
83: ; preds = %54, %39
%84 = phi i64 [ 0, %39 ], [ %80, %54 ]
%85 = icmp eq i64 %50, 0
br i1 %85, label %98, label %86
86: ; preds = %83
%87 = getelementptr inbounds double, double* %10, i64 %84
%88 = bitcast double* %87 to <2 x double>*
%89 = load <2 x double>, <2 x double>* %88
%90 = getelementptr inbounds double, double* %2, i64 %84
%91 = bitcast double* %90 to <2 x double>*
%92 = load <2 x double>, <2 x double>* %91
%93 = fneg <2 x double> %92
%94 = fmul <2 x double> %42, %93
%95 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %44, <2 x double> %89, <2 x double> %94)
%96 = fdiv <2 x double> %95, %46
%97 = bitcast double* %87 to <2 x double>*
store <2 x double> %96, <2 x double>* %97
br label %98
98: ; preds = %83, %86
%99 = icmp eq i64 %40, %30
br i1 %99, label %140, label %100
100: ; preds = %32, %29, %98
%101 = phi i64 [ 0, %32 ], [ 0, %29 ], [ %40, %98 ]
%102 = xor i64 %101, -1
%103 = and i64 %30, 1
%104 = icmp eq i64 %103, 0
br i1 %104, label %115, label %105
105: ; preds = %100
%106 = getelementptr inbounds double, double* %10, i64 %101
%107 = load double, double* %106
%108 = getelementptr inbounds double, double* %2, i64 %101
%109 = load double, double* %108
%110 = fneg double %109
%111 = fmul double %110, %3
%112 = tail call double @llvm.fmuladd.f64(double %25, double %107, double %111)
%113 = fdiv double %112, %27
store double %113, double* %106
%114 = or i64 %101, 1
br label %115
115: ; preds = %105, %100
%116 = phi i64 [ %101, %100 ], [ %114, %105 ]
%117 = sub nsw i64 0, %30
%118 = icmp eq i64 %102, %117
br i1 %118, label %140, label %119
119: ; preds = %115, %119
%120 = phi i64 [ %138, %119 ], [ %116, %115 ]
%121 = getelementptr inbounds double, double* %10, i64 %120
%122 = load double, double* %121
%123 = getelementptr inbounds double, double* %2, i64 %120
%124 = load double, double* %123
%125 = fneg double %124
%126 = fmul double %125, %3
%127 = tail call double @llvm.fmuladd.f64(double %25, double %122, double %126)
%128 = fdiv double %127, %27
store double %128, double* %121
%129 = add nuw nsw i64 %120, 1
%130 = getelementptr inbounds double, double* %10, i64 %129
%131 = load double, double* %130
%132 = getelementptr inbounds double, double* %2, i64 %129
%133 = load double, double* %132
%134 = fneg double %133
%135 = fmul double %134, %3
%136 = tail call double @llvm.fmuladd.f64(double %25, double %131, double %135)
%137 = fdiv double %136, %27
store double %137, double* %130
%138 = add nuw nsw i64 %120, 2
%139 = icmp eq i64 %138, %30
br i1 %139, label %140, label %119
140: ; preds = %115, %119, %98, %23, %21
ret void
}