Post Apple Announcement Letdown

sadmacMy fanboism toward Apple has been waning for the last few years. Apple does not seem to share my priorities. A few examples:

  • I find no value in the Apple Watch.
  • I think that computing should be done from proper computer, and not an iPad or iPhone.
  • Focusing on the iOS and social integration into Mac OS X instead of more pressing matters (Like a new File System, or simply some bug fixes!) is a mistake.

Misleading The Fans

hello_again_event

This most recent announcement just about seals it though. The advertisement for the event featured the words “hello again.” For loyal Apple customers, this phrase has significant meaning, as it was central to the marketing that marked the rebirth of Apple with the introduction of the iMac by Steve Jobs.

imac-hello-again

When they used this phrase with the iMac, Apple was referencing an even earlier product that marked a significant shift in computing in the 1980’s. The original Macintosh. The first promotional shot of this computer-that-changed-everything had the playful “hello” welcoming user’s to its new graphical user interface.

Apple set up the long-time fans of Apple for something revolutionary. Something that would be amazing, and something most-certainly to do with the iMac, which is frankly Apple’s core product. It is the emblem of Apple and their revitalization in the 90’s. They had to know those words would make us expect an iMac announcement; especially after Microsoft’s announcement the day before, featuring the iMac like surface computer that works like a tablet.

microsoft_surface_studio_all_in_one_desktop_computer_1MacBooks

But instead of updating the iMac (or the MacMini or the MacPro…), they spent the majority of the time lauding the new MacBook Pro computers.

Let’s review all the amazing features that professionals were fervently waiting for:

  • They are thinner! (I’d rather have better heat dissipation, a better graphics card, and more battery capacity)
  • They have more pixels! (But I already have a large display on my desktop that I plug into)
  • There is a touchbar! (I don’t like having to look at what I am touching. Physical keys don’t jump around and can be felt without looking)
  • The track pad is bigger! (Was the previous track pad too small?)

Its not all superfluous though. There are some cool features that are exciting:

  • Touch id for logging in is a cool and novel feature.
  • USB3/Thunderbolt 3 does have interesting prospects since any port can be used for anything, including charging. (As long as they don’t change the port in 2 years and make us buy all new peripherals again…)
  • 2 TB SSD with 3 GB/s read/write speeds

Overall, it felt like a very weak press conference. It’s clear that they just don’t care about the desktop user. They want to appeal to young on-the-go people and their wallets.

Additionally Apple has been slowly killing useful features from their laptops for quite sometime. Here’s a brief list of the once common features that I wish were still present.

  • Battery Indicator Lights – Nice to check battery level without having to open up the laptop, and wait for it to power up
  • Non-soldered RAM – It used to be nice upgrading the RAM down the line, which would be more cost efficient. Admittedly, this isn’t to Apple’s favor though
  • Replaceable Battery – Less of a problem now than it used to be, still would be nice
  • IR Reciever  -Useful for presentation where you don’t want to be worrying about Bluetooth, or wifi connectivity. Also nice for playing movies if you use your Mac as a TV.
  • Sleep Indicator Light – nice to be able to tell is machine is sleeping or powered off
  • Magsafe Adapter – One of my favorite features to disappear. It has saved my laptop many times!
  • Glowing Apple – Not useful per-se, but definitely symbolic of Apple’s soul for the last decade!
  • Startup Chime – Useful for diagnostics, indicates that the hardware is working

No More Displays, No More Desktops?

lg5kmonitor-800x725

Another nail in the coffin for the desktop line is the fact that they endorsed an LG display for use with MacBooks. To me this signals that Apple will shortly discontinue the MacPro and MacMini line of computers. Apple tends not to use other company’s products in promotional shots and advertisements. The only two products without screens no longer have an Apple-branded screen to showcase and buy (and this screen certainly doesn’t exactly scream Apple). I don’t think this bodes well.

Less-Confusing Monikers?

Tangentially, their whole ecosystem has been very clumsily named lately. (Another problem reminiscent of the 1990’s Apple). They have Airs, Pros, Minis, and other dizzying designations that aren’t consistently used. What makes a Pro a Pro? Why was the MacBook smaller than the MacBook Air? Why is the MacMini not called the MacAir?

I propose a simpler, and far less confusing lineup across all products. There would only be 3 designations to differentiate product sizes, and two prefixes to differentiate between computers and devices. Please see the chart below:

proposedlineupConclusion

I hope Apple realizes that the Professional and Enthusiast users are important. For the last 30 years, the enthusiast and pro-sumer market has been Apple’s evangelists. This market would convince friends and family to purchase Apple products. If Apple Alienates these enthusiastic individuals, it could end up hurting their sales in the long run.

As for myself, I just can’t get excited about an Apple product until they release a decent desktop machine.

Illustrator CS5 on El Capitan

Adobe_Illustrator_CS5_icon

I’ve been sticking with Adobe’s CS5 for quite a while now. I had planned on upgrading when CS7 was released… However Adobe decided to go with the cloud-based option, and I’m not ready to have another monthly-fee to worry about.

At any rate, my plan of sticking with CS5 was going just fine until El Capitan came out. 3 (interrelated) problems arose which made using Adobe Illustrator less than ideal.

  1. Adobe Illustrator would crash on exit
  2. Since it crashes on exit, the preferences would never get updated
  3. Since the preferences never get updated, certain settings would need to get changed every time I opened AI.

It was frustrating, but it still wasn’t a deal breaker. I looked online to see if anyone had any solutions. In this post at the official Adobe forums, there was someone asking my exact question. The official response for the thread though was “CS5 is not supported. Update to creative cloud.” Not the answer I was looking for…

As I went deeper, there was another popular suggestion: Downgrade to Yosemite if you are too cheap to upgrade to the newest Illustrator. While that would resolve one problem, it would introduce other issues. Yosemite no longer receives all of the security patches that come with El Capitan. Apple only pushes them out to the newest OS unless it’s super-critical. I’m not willing to give up security for this minor of an issue.

Finally, after wading through multiple pages of this post, a user produced a tip that amazingly solved the issue.

Rename “/Library/Application Support/Adobe/CS5.5ServiceManager” to “/Library/Application Support/Adobe/CS5.5ServiceManager.bak”

This resolved the issue. I’m annoyed that it wasn’t marked as the thread’s solution to the problem, as it is (in my opinion) the best solution to the problem. Illustrator is now working again as it always had before upgrading to El Capitan. I hope that this helps someone else who is having a hard time finding the solution to this annoying issue.

Project Euler: 10

check

Problem 10 of Project Euler is to find the sum of all primes under 2,000,000.

This isn’t a hard problem in most languages. I have recently been going through and re-solving problems in various languages for the fun of it. Just for fun, I decided to solve some problems using Bash scripting. Bash has all the constructs of a real programming language, however, the main draw back for problems like this is that it’s slow. VERY slow. Well, lets see what we can do to speed this problem up.

Brute Force

The brute force approach is pretty simple. Loop through every number, n, less than 2,000,000, and try dividing it by every number from 2 to n-1. If it is divisible, break out of the loop and try the next number.

sum=2
for (( i=3; i<2000000; i++ )); do
    prime=1
    for (( d=2; d<$i; d++ )); do
    if [ $(($i % $d)) -eq 0 ]; then
        prime=0
        break;
    fi
    done
    if [ $prime -eq 1 ]; then
    sum=$(($sum + $i))
    fi
done
echo $sum

This solution has no optimization, but will still yield a result in a relatively small time-frame for most languages. This would take incredibly long to process primes smaller than 2,000,000. For a benchmark, I have run this through primes less than 2,000, and it took 6.430 seconds. We need to optimize.

Optimize

There are a lot of simple changes that we can do to get our compute times down. For instance, if we only loop through odd numbers, we have half as many to process.

Another classic technique to optimize a prime test is to check for factors less than or equal to the square root of the number. The reason this works is that if a factor of our number, n, is larger than the square root of n, we will find the other factor has to be smaller than the square root of n, and will thus be detected.

sum=2
for (( i=3; i<2000; i+=2 )); do
    prime=1
    for (( d=2; d*d<=$i; d++ )); do
    if [ $(($i % $d)) -eq 0 ]; then
        prime=0
        break;
    fi
    done
    if [ $prime -eq 1 ]; then
    sum=$(($sum + $i))
    fi
done
echo $sum

These two changes alone bring our compute time down to .319 seconds for primes under 2,000! I still wouldn’t recommend trying computing all primes under 2,000,000. I tried, and killed it after 3 days without a result!

Sieve of Eratosthenes

Prime sieves are a super fast way of computing prime numbers without having to do any division. This method is attributed to Eratosthenes of Cyrene, a Greek mathematician living about 200 BC. (You can read more about the history on Wikipedia).

Basically, you have an array of every number you want to check. Start by making each element of the array equal to 1, indicating it is a prime.  Go through the array, starting at two. Whenever you hit a value that is 1, mark all the multiples of that value as 0’s. So, we look at element 2, which is prime because it’s value is 1. element whose index is a multiple of 2 should then get marked as 0, since that cannot be prime. You then advance to the next element, and repeat until you’ve visited every number in the array.

limit=2000
primes[$limit]=0
primeList[0]=2
primeIndex=0
sum=0
for (( i=2; i<$limit; i++ )); do
    if [[ ${primes[$i]} -eq \0 ]]; then
        sum=$(($sum+$i))
        primeList[$primeIndex]=$i
        primeIndex=$(($primeIndex+1))
        for (( n=$i; n<$limit; n+=$i )); do
            primes[$n]=1
        done
    fi
done

echo $sum

Implementing this method definitely improves results for our benchmark of primes less than 2,000; .186 seconds! However, this approach does not scale up to the desired 2,000,000 because Bash arrays are super slow as they get larger. Even though this approach worked great in our benchmark, it will still take upwards of 3 days to complete for all the primes under 2,000,000.

Combination of Methods

By using a sieve method combined with our optimized method, I was able to finally get the correct answer in 34 minutes using a Bash script.

I used a sieve to generate the primes between 1 and sqrt(2000000). This was fast since the array wasn’t nearly as big. I then used the array of primes that I generated to check every odd number between 2 and 2,000,000.

Another shortcut to reduce computation is to make a second array containing the squares of each prime. This means that we don’t need to perform multiplication in each loop when we are checking for primality.

limit=2000000
sum=0

# Generate primes up to sqrt of 2000000 using sieve
primeLimit=$(echo "scale=0;sqrt($limit*2)" | bc)
primes[$primeLimit]=0
primeList[0]=2
primeListSquared[0]=4
primeIndex=0
for (( i=2; i<$primeLimit; i++ )); do
    if [[ ${primes[$i]} -eq \0 ]]; then
        sum=$(($sum+$i))
        primeList[$primeIndex]=$i
        primeListSquared[$primeIndex]=$i*$i
        primeIndex=$(($primeIndex+1))
        for (( n=$i; n<$primeLimit; n+=$i )); do
            primes[$n]=1
        done
    fi
done

# Make sure primeLimit is an odd number
[[ $(($primeLimit % 2)) -eq 0 ]] && primeLimit=$(($primeLimit + 1))

# Use known primes from above to check each remaining number for primality
for (( i=$primeLimit; i<$limit; i+=2 )); do
    prime=1
    for (( p=0; ${primeListSquared[$p]}<=$i; p++ )); do
        if [[ $(($i % ${primeList[$p]})) -eq 0 ]]; then
            prime=0
            break
        fi
    done
    # Record!
    if [[ $prime -eq 1 ]]; then
        sum=$(($sum+$i))
    fi
done

echo $sum

34 minutes. Finally, a “reasonable” result (by some definitions of reasonable).

Multi-Processing

The last step I took was by splitting up the task of finding primes into multiple processes. This allowed all 8 of my cores to work on the solution. I moved my prime search method into a function that took a start and stopping point as parameters, and then echoed the sum for that portion back to a while loop that added them all together.

limit=2000000

# Generate primes up to sqrt of limit
primeLimit=$(echo "scale=0;sqrt($limit*2)" | bc)
primes[$primeLimit]=0
primeList[0]=2
primeListSquared[0]=4
primeIndex=0
for (( i=2; i<$primeLimit; i++ )); do
    if [[ ${primes[$i]} -eq \0 ]]; then
        primeList[$primeIndex]=$i
        primeListSquared[$primeIndex]=$i*$i
        primeIndex=$(($primeIndex+1))
        for (( n=$i; n<$primeLimit; n+=$i )); do
            primes[$n]=1
        done
    fi
done

function checkRange() {
    start=$1
    end=$2
    rangeSum=0

    # Make sure range starts at an odd number
    [[ $start -lt 2 ]] && start=3 && rangeSum=2
    [[ $(($start % 2)) -eq 0 ]] && start=$(($start + 1))

    # Use known primes to check all remaining numbers for primality
    for (( i=$start; i<$end; i+=2 )); do
        prime=1
        for (( p=0; ${primeListSquared[$p]}<=$i; p++ )); do
            if [[ $(($i % ${primeList[$p]})) -eq 0 ]]; then
                prime=0
                break
            fi
        done
        # Record!
        if [[ $prime -eq 1 ]]; then
            rangeSum=$(($rangeSum+$i))
        fi
    done
    echo $rangeSum
}

# Split up task into chunks, and check with multiple processes
sum=0
range=$(($limit / 50))
for (( start=0; start<$limit; start+=$range )); do
    checkRange $start $(($start+$range)) &
done | while read result; do
    sum=$(($sum+$result))
    echo $sum
done | tail -1

This method brought the compute time down to 3 minutes 22.075 seconds.

Conclusion

Project Euler gives the guideline that if your solution takes more than a minute, you’re probably doing it wrong. For this particular task though, I think 3 minutes is rather successful given the constraints of Bash. It was a fun project to try to optimize such a relatively simple algorithm within the constraints of this little scripting language.

If you can find any way to speed up the results, please let me know!

Visit the solution on my GitHub page.

© 2007-2015 Michael Caldwell