Hi all, I am currently compiling R to RISC-V64 CPU and I think I have discovered a NA propagation failure. How R implements NA (not available) and NaN (not-a-number) is explained in detail here: https://stat.ethz.ch/pipermail/r-devel/2014-February/068380.html. In short, according to my understanding of R's convention, any calculation involving NA but no NaN should result in NA (called NA propagation), and any calculation involving NaN but no NA should result in NaN. Calculations involving both NA and NaN can result in either value. While many R functions handle this logic in their source codes, basic arithmetic operations such as +-/* throw it to the hardware to handle. However, the RISC-V64 CPU does not behave as expected, at least the CPU I am using (Starfive JH7100-7110). Here are the relevant bit patterns. From my understanding, as IEEE only regulates the bit patterns of NaN, R picks one of the bit patterns (ending with 07a2) and declares it as NA. # print_hex is a function to print the bit pattern in hex> print_hex(0.1)3fb999999999999a # same for RISC-V> print_hex(NaN)7ff8000000000000 # same for RISC-V> print_hex(NA)7ff00000000007a2 # same for RISC-V> print_hex(NA+1)7ff80000000007a2 # 7ff8000000000000 in RISC-V> print_hex(NA*1)7ff80000000007a2 # 7ff8000000000000 in RISC-V> print_hex(NaN*1)7ff8000000000000 # same for RISC-V Therefore, in RISC-V64, all basic arithmetic operations involving NA give NaN.> NA+1[1] NaN This failure in NA propagation may cause many R packages like mice to not work properly, and results in the `make check` test in the `stats` package to fail. Example from the make check test: xn <- 1:4 yn <- c(1,NA,3:4) xout <- (1:9)/2 data.frame(approx(xn,yn, xout, na.rm=FALSE, rule = 2)) # failure, some values should be NA but it turns out NaN I am reaching out to the R community looking for help in solving this problem. Does anyone around here have any hints or ideas on how to solve this issue? Currently, my hacky implementation is to stop the NA operand before it goes to the hardware and directly return NA as the output. However, this solution may penalize performance significantly, so I am looking for any alternative idea. Thank you for your time and consideration! Best regards, Jane He _________ University of California, Irvine Student of Master of Software Engineering 2022-2023 cohort [[alternative HTML version deleted]]
On Thu, 23 Feb 2023 15:39:08 -0800 Jane He <siyaoh4 at uci.edu> wrote:> In short, according to my understanding of R's convention, any > calculation involving NA but no NaN should result in NA (called NA > propagation), and any calculation involving NaN but no NA should > result in NaN. Calculations involving both NA and NaN can result in > either value.The ?NA help page already contains a warning that "future CPUs and/or compilers" may prevent NA from resulting in computations with NA. A similar problem has been encountered on Apple processors, but a workaround was found there: https://blog.r-project.org/2020/11/02/will-r-work-on-apple-silicon/#nanan-payload-propagation> This failure in NA propagation may cause many R packages like mice to > not work properly, and results in the `make check` test in the > `stats` package to fail.Perhaps the way forward is to update the tests. Regarding R packages, since is.na() is already documented to return TRUE for all NaNs, not only the NA value, it should be possible to make them work even if they currently fail. -- Best regards, Ivan
Tomas Kalibera
2023-Feb-24 13:09 UTC
[Rd] Possible NA Propagation Failure in RISC-V64 CPU?
On 2/24/23 00:39, Jane He wrote:> Hi all, > > I am currently compiling R to RISC-V64 CPU and I think I have discovered a > NA propagation failure. > > How R implements NA (not available) and NaN (not-a-number) is explained in > detail here: > https://stat.ethz.ch/pipermail/r-devel/2014-February/068380.html. > > In short, according to my understanding of R's convention, any calculation > involving NA but no NaN should result in NA (called NA propagation), and > any calculation involving NaN but no NA should result in NaN. Calculations > involving both NA and NaN can result in either value. > > While many R functions handle this logic in their source codes, basic > arithmetic operations such as +-/* throw it to the hardware to handle. > However, the RISC-V64 CPU does not behave as expected, at least the CPU I > am using (Starfive JH7100-7110). > > Here are the relevant bit patterns. From my understanding, as IEEE only > regulates the bit patterns of NaN, R picks one of the bit patterns (ending > with 07a2) and declares it as NA. > > # print_hex is a function to print the bit pattern in hex >> print_hex(0.1) > 3fb999999999999a # same for RISC-V >> print_hex(NaN) > 7ff8000000000000 # same for RISC-V >> print_hex(NA) > 7ff00000000007a2 # same for RISC-V >> print_hex(NA+1) > 7ff80000000007a2 # 7ff8000000000000 in RISC-V >> print_hex(NA*1) > 7ff80000000007a2 # 7ff8000000000000 in RISC-V >> print_hex(NaN*1) > 7ff8000000000000 # same for RISC-V > > > Therefore, in RISC-V64, all basic arithmetic operations involving NA give > NaN. > >> NA+1 > [1] NaN > > This failure in NA propagation may cause many R packages like mice to not > work properly, and results in the `make check` test in the `stats` package > to fail. Example from the make check test: > > xn <- 1:4 > yn <- c(1,NA,3:4) > xout <- (1:9)/2 > data.frame(approx(xn,yn, xout, na.rm=FALSE, rule = 2)) # failure, some > values should be NA but it turns out NaN > > I am reaching out to the R community looking for help in solving this > problem. Does anyone around here have any hints or ideas on how to solve > this issue? > > Currently, my hacky implementation is to stop the NA operand before it goes > to the hardware and directly return NA as the output. However, this > solution may penalize performance significantly, so I am looking for any > alternative idea. > > Thank you for your time and consideration!Please see this bug report for a related discussion: https://bugs.r-project.org/show_bug.cgi?id=18416 This is a known problem and has been discussed a number of times before RISC-V. Still, RISC-V is a bit unique architecture in that it deliberately does not propagate NaN payloads at all and it cannot be enabled. R's distinction of NA vs NaN however depends on that propagation. The propagation of NAs through computations in R is not reliable even on other current platforms (due to what the hardware does, but also what the compilers and libraries do, see e.g. ?NaN) and technically it is not guaranteed and R packages are advised not to depend on it, but various package checks and existing software adjusted to how the propagation happens to work on widely used platforms, now probably mostly x86_64. 64-bit ARM is even a bit more friendly to R than that (when the CPU is switched to such mode, which R does). If RISC-V supported such mode, R would enable it as well, but it deliberately does not support it. Good defensive portable code would not depend on the propagation to happen in hardware/compilers but add checks in software, if propagation was needed. I doubt that the performance overhead would be too high if done well, particularly for vectorized computations, but it will be noticeable and in some cases may be high. This would have to include special handling of data including NAs when they are passed to external numerical libraries, which would be a lot of work to implement and maintain, it seems unrealistic. At the same time there is no strong incentive to do so: people who want the propagation seem to be reasonably happy with how it happens to work on major platforms. For the current R to work well on RISC-V, really, the platform would have to support the propagation, at least optionally, perhaps like 64-bit ARM. Unless major platforms in the future stop supporting the propagation, I am skeptical anything major could change on the R side. Best Tomas> > Best regards, > Jane He > > _________ > University of California, Irvine > Student of Master of Software Engineering > 2022-2023 cohort > > [[alternative HTML version deleted]] > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel