Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9270493
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 18, 20262026-06-18T15:23:02+00:00 2026-06-18T15:23:02+00:00

The following code truncates a number of type Double to one in the type

  • 0

The following code truncates a number of type Double to one in the type Word16 (although I suspect any other word type behaves similarly, I had to choose one for the example).

truncate1 :: Double -> Word16
truncate1 = fromIntegral . (truncate :: Double -> Int)

As you can read, I first truncate it to Int and only then I cast it to Word16. I benchmarked this function agains a direct truncation:

truncate2 :: Double -> Word16
truncate2 = truncate

Surprisingly to me, the first version (going thru the Int type first) performed much better. Or the second much worse. According to the criterion output:

benchmarking truncate/truncate1
mean: 25.42399 ns, lb -47.40484 ps, ub 67.87578 ns, ci 0.950
std dev: 145.5661 ns, lb 84.90195 ns, ub 244.2057 ns, ci 0.950
found 197 outliers among 100 samples (197.0%)
  97 (97.0%) low severe
  100 (100.0%) high severe
variance introduced by outliers: 99.000%
variance is severely inflated by outliers

benchmarking truncate/truncate2
mean: 781.0604 ns, lb 509.3264 ns, ub 1.086767 us, ci 0.950
std dev: 1.436660 us, lb 1.218997 us, ub 1.592479 us, ci 0.950
found 177 outliers among 100 samples (177.0%)
  77 (77.0%) low severe
  100 (100.0%) high severe
variance introduced by outliers: 98.995%
variance is severely inflated by outliers

To be honest, I just started using Criterion, so I’m not an expert using it, but I understand that 25.42399 ns is a shorter execution time than 781.0604 ns. I suspect that some specialization is playing a role here. Is it truncate2 too slow? Being the case, can truncate be improved? Furthermore, anybody knows an even faster way? I feel like doing something wrong casting to a type I don’t really use.

Thanks in advance.

I am compiling with GHC-7.4.2, optimizations enabled (-O2).

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-18T15:23:03+00:00Added an answer on June 18, 2026 at 3:23 pm

    First, note that the module GHC.Word includes the following RULE pragma:

    "truncate/Double->Word16"
        forall x. truncate (x :: Double) = (fromIntegral :: Int -> Word16) (truncate x)
    

    This is a simple rewrite rule to perform precisely the optimization your truncate1 provides. So we have a few questions to consider:

    Why is this an optimization at all?

    Because the default implementation of truncate is generic, to support any Integral instance. The speed difference you see is the cost of that generality; in the specific case of truncating one primitive type to another, there are much faster methods available.

    So it seems that truncate1 is benefiting from a specialized form, while truncate2 is not.

    Why is truncate1 faster?

    In GHC.Float, where the RealFrac instance for Double is defined, we have the following RULE pragma:

    "truncate/Double->Int"              truncate = double2Int
    

    Where double2Int is the optimized form we want. Compare this to the RULE mentioned earlier–apparently there’s no similar primitive operation specifically for converting Double to Word16.

    Why doesn’t truncate2 get rewritten as well?

    Quoth the GHC User’s Guide:

    GHC currently uses a very simple, syntactic, matching algorithm for matching a rule LHS with an expression. It seeks a substitution which makes the LHS and expression syntactically equal modulo alpha conversion. The pattern (rule), but not the expression, is eta-expanded if necessary.

    Expressions being matched are not eta-expanded, which is to say that a rule matching on forall x. foo x will match in bar y = foo y but not in bar = foo.

    Since your definitions are all written point-free, the RULE for Double -> Int matches, but the RULE for Double -> Word16 does not.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Following code gets executed whenever I want to persist any entity. Things seems to
I was going through the following code. It basically truncates the the digits of
The following code seems to work if there is one user, but truncate the
I have the following Haskell code import Data.Int import System.Environment type Coord = (Int16,
Following code produces a nested array as a result for keys containing three items:
Following code takes like 2500 milliseconds on an i7-*3.4 GHz windows-7 64-bit computer to
Following code worked fine abstract class FunctionRunnable<V> implements Runnable { protected abstract V calculate();
Following code: <%= render 'shared/error_messages', f.object %> where f.object is instance of a class
Following code is a pretty simple and complete JQuery Dialog. Everything works. Problem is
Following code is generated by a for loop. <form action=saveresponse.php method=POST name=mainForm> <input class=cbox_yes

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.